JavaScript的事件循环(Event Loop)

一:任务队列

所有任务可以分为两种:一种是同步任务,另一种是异步任务。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
异步任务:不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

二:JavaScript的运行机制

(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个“任务队列”。只要异步任务有了运行结果,就在“任务队列”之中放置一个事件。
(3)一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
只要主线程空了,就会去读取“任务队列”,这就是JavaScript的运行机制。这个过程会不断重复。

三:Event Loop

1.概念
主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这个运行机制又称为Event Loop(事件循环)。

2.宏任务和微任务

宏任务(MacroTask/Task):script全部代码、setTimeout、setInterval、setImmediate、I/O、UI Rendering。
微任务(MicroTask):Process.nextTick、Promise、Object.observe(废弃)、MutationObserver

3.执行过程
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务(microTask)队列是否为空,如果为空的话,就执行Task(宏任务),否则就一次性执行完所有微任务。每次单个宏任务执行完毕后,检查微任务(microTask)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask)后,设置微任务(microTask)队列为null,然后再执行宏任务,如此循环。

简而言之:同步环境执行 -> 事件循环1(microtask queue的All)-> 事件循环2(macrotask queue中的一个) -> 事件循环1(microtask queue的All)-> 事件循环2(macrotask queue中的一个)…

利用microtask queue可以形成一个同步执行的环境,但如果Microtask queue太长,将导致Macrotask任务长时间执行不了,最终导致用户I/O无响应等,所以使用需慎重。

4.例子

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});
console.log('script end');

执行结果

script start
script end
promise1
promise2
setTimeout

对微任务和宏任务的执行顺序的个人理解

猜你喜欢

转载自blog.csdn.net/wytraining/article/details/109357354