javascript是一门单线程语言,异步和多线程是靠事件循环机制(Event Loop
)实现的
同步|异步任务
【执行过程】
-
从广义的角度来看,js代码从上到下解析执行,遇到
同步任务
就压入调用栈
执行,遇到异步任务
就压入Event Table
,并等待触发进入任务队列
。 -
等
同步任务
执行完毕后,也就是调用栈为空时,将处于任务队列
中的任务压入调用栈
执行。 -
js引擎会持续检查
调用栈
是否为空,一旦为空,就会去任务队列
那里检查是否有等待被调用的任务,并将其压入栈中,重复这种循环的行为叫做事件循环
宏|微任务
如果从微观的角度来看,任务实际分为微任务和宏任务
- 微任务:Promise的
then
|catch
,MutationObserver
,process.nextTick
(Node) - 宏任务:
script
(主程序代码),定时器
,AJAX
,事件
,setImmediate
(Node),I/O
(Node),UI render
(渲染)
所以事件循环可以更细致的分为:
【执行过程】
- 先将
script
(主程序代码)压入调用栈执行,遇到宏任务
和微任务
时压入Event Table
中,等待触发并进入任务队列
中相应的宏|微队列
。 - 待调用栈为空后,**先将
微任务队列
入栈执行,**调用栈空后,再将宏任务队列
入栈执行,整个过程为一次事件循环。
总结下来就是,script
(主程序代码)->微任务->宏任务->微任务->宏任务->微任务->宏任务…
console.log('1');
setTimeout(() => {
console.log('2');
},0);
Promise.resolve().then(() => {
console.log('5');
})
new Promise((resolve) => {
console.log('3');
resolve();
}).then(() => {
console.log('4');
})
//13542
定时器
定时器实际上是不准的
定时器的实际含义是:多少秒后,将任务从Event Table
压入 任务队列
同步任务长期阻塞的话,即使时间到了,定时器也需要等待同步任务执行完毕后,才能压入栈中
但如果回调函数的时间
超过了延迟时间,那么就完全看不出来有时间间隔了