1.事件循环的理解
JavaScript是单线程的,意味着它一次只能执行一个任务。而事件循环就是去协调在JavaScript环境中运行的同步任务、异步任务(微任务、宏任务)的执行顺序的一种机制。它是 JavaScript 实现单线程非阻塞异步执行的核心。
2.事件循环的执行顺序
同步任务——>所有微任务——>一个宏任务——>清空微任务队列——>一个宏任务.......。每执行完一个宏任务后,再次检查并执行所有微任务,然后再执行一个宏任务,这就是事件循环。
宏任务:指的是最普通的异步工作,如:setTimeout、setInterval、整段 script、I/O 回调(网络请求、文件读写等)。事件循环每轮只从宏任务队列里取一个执行。
微任务:包括Promise.then、queueMicrotask、MutationObserver(以及 Node 里的 process.nextTick)。微任务在当前宏任务执行完后立马执行。
代码示例:执行顺序(A->D->C->B)
console.log('A');setTimeout(() => console.log('B'), 0); // 宏任务Promise.resolve().then(() => console.log('C')); // 微任务console.log('D');
3.扩展
对于添加async和await语法糖来说,async会将异步函数 ‘变为’ 同步函数,而await会等待Promise返回的结果后,才会执行await下面的语句,也就是说await把后面的语句注册为为微任务,而await前面的任务为同步任务。
代码示例:执行顺序(1->2->3->4->5->6->7)
console.log('1. 同步代码开始');async function foo() {console.log('2. foo 函数体执行(同步)');await bar(); // await 后面那一行是微任务console.log('5. await 后面是微任务,此时 bar 已返回');
}function bar() {console.log('3. bar 执行(同步)');return Promise.resolve(); // 返回一个已决的 Promise
}foo().then(() => {console.log('6. foo 返回的 Promise resolve(微任务)');
});setTimeout(() => {console.log('7. setTimeout 回调(宏任务)');
}, 0);console.log('4. 同步代码结束');