Event Loop即事件循环
是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理
任务队列
任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
- (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
- (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- (4)主线程不断重复上面的第三步。
只要主线程空了,就会读取任务列队,
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。
执行栈中的代码(同步任务),总是在读取"任务队列"(异步任务)之前执行
js事件还可以分为宏任务微任务
macrotask(宏任务):
script(整体代码), XHR回调、事件回调(鼠标键盘事件)setTimeout, setInterval, setImmediate(node独有), I/O, UI rendering
microtask(微任务):process.nextTick(node独有), Promises.then, Object.observe(废弃), MutationObserver
详细步骤:
1.选择当前要执行的宏任务队列,选择一个最先进入任务队列的宏任务,如果没有宏任务可以选择,则会跳转至microtask的执行步骤。
2.将事件循环的当前运行宏任务设置为已选择的宏任务。
3.运行宏任务。
4.将事件循环的当前运行任务设置为null。
5.将运行完的宏任务从宏任务队列中移除。
6.microtasks步骤:进入microtask检查点。
7.更新界面渲染。
8.返回第一步。
注意:1、宏队列macrotask一次只从队列中取一个任务执行,执行完后就去执行微任务队列中的任务;
2、微任务队列中所有的任务都会被依次取出来执行,知道microtask queue为空;
再附上一道题
console.log("start")
async function f1(){console.log("f1 start")var aa= await 1;
setTimeout(function(){console.log("setTimeout 2")
},0)
}
setTimeout(function(){console.log("setTimeout ")
},0)
var pr1 =new Promise(function(resolve){console.log(" promise start ")resolve();
}).then(function(resoult){console.log("promise then")
})
f1();
console.log("end")
结果: start=>promise start=> f1 start=> end=> promise then =>setTimeout=>setTimeout 2