前言
之前学习的时候对js中事件队列不是很了解,参考了很多资料,小小总结一下。
(本文只用于自身学习,作为资料保存)
一、同步任务和异步任务
JavaScript是一门单线程语言,所谓单线程,就是指一次只能完成一件任务,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务。但如果有一个任务的执行时间很长,比如文件的读取或者数据的请求等等,那么后面的任务就要一直等待,这就会影响用户的使用体验。
为了解决这种情况,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
同步模式就是前一个任务执行完成后,再执行下一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的;
异步模式则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行队列上的后一个任务,而是执行回调函数;后一个任务则是不等前一个任务的回调函数的执行而执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
二、事件队列和事件循环
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册回调函数
· 当指定的事情完成时,Event Table会将这个函数移入Event Queue ,等待主线程的任务执行完毕
· 当栈中的代码执行完毕,执行栈(call stack)中的任务为空时,就会读取任务队列(Event quene)中的事件,去执行对应的回调
· 如此循环,就形成js的事件循环机制(Event Loop)

三、宏任务和微任务
还有一个问题,就是SetTimeout和promise都是异步任务,那么它们两个先执行谁呢?
其实在js中也是有一个机制,就是会分为宏任务和微任务。宏任务和微任务分别存放在不同的event loop,这两个队列分别为macrotack queue和microtack queue.
Macrotack(宏任务):
script(整体代码)、setTimeout、setInterval、setImmediateI/O、UI交互事件、postMessage、MessageChannel
Microtack(微任务):
Promise.then、MutationObserver、process.nextTick(Node环境)
宏任务和微任务的执行流程,大体可以分为:
当执行栈中的任务清空,主线程会先检查微任务队列中是否有任务,如果有,就将微任务队列中的任务依次执行,直到微任务队列为空,之后再检查宏任务队列中是否有任务,如果有,则每次取出第一个宏任务加入到执行栈中,之后再清空执行栈,检查微任务,以此循环,直到全部的任务都执行完成。

看完上面的流程,我们来试着看一段代码的执行结果
console.log("整体script开始");
setTimeout(() => {
console.log("setTimeout");
}, 0);
let promise = new Promise(resolve => {
console.log("promise1");
resolve();
}).then(data => {
console.log("then1");
}).then(data => {
console.log("then2");
});
console.log("end");
按照上面的代码,js由上到下开始执行
1.首先,遇到同步任务先输出“整体script开始”
2.遇到setTimeout,将其挂起,放入到宏任务队列,继续往下执行
3.new Promise()是立即执行的,所以输出的是“promise”,而Promise.then是微任务,会依次排到微任务队列中。
4.继续向下输出“end”,现在执行栈中的任务已经清空了,再看微任务队列有没有任务
5.发现Promise.then在微任务队列中,取出放入执行栈中执行,一直执行将微任务队列清空
5.最后再从宏任务中取出setTimeout
输出结果如图:

四、总结
1.js解析方法时,将同步任务排队到执行栈中,异步任务排队到事件队列中。
2.事件队列分为:
宏任务:script(整体代码)、setTimeout、setInterval、setImmediateI/O、UI交互事件、postMessage、MessageChannel
微任务:Promise.then、MutationObserver、process.nextTick(Node环境)
3.浏览器环境中执行方法时,先将执行栈中的任务清空,再将微任务推到执行栈中并清空,之后检查是否存在宏任务,若存在则取出一个宏任务,执行完成检查是否有微任务,以此循环…
4.Event Loop在浏览器与node环境中的区别:
浏览器环境每次执行一个宏任务,再去检查微任务
node会清空当前所处阶段的队列,即执行所有task,再去检查微任务
参考连接
https://www.jianshu.com/p/667a20d008cf
https://zhuanlan.zhihu.com/p/41543963
947

被折叠的 条评论
为什么被折叠?



