例子一
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
- 整段代码做为宏任务,进入主线程
- 遇到
setTimeout
,将其回调函数注册后分发到宏任务事件队列中(作为下一次循环宏任务调用) - 接下来遇到了
Promise
,new Promise
立即执行,打印'promise',then
函数分发到微任务事件队列(本次宏任务的微任务) - 遇到
console.log()
,立即执行 - 整体代码作为第一次循环的宏任务执行结束,查看还有微任务
then
,执行 - 开始第二次循环,执行
setTimeout
,打印'promise' - 结果:promise, console, then, setTimeout
例子二
console.log('Hello World!');
const p1 = new Promise((resolve) => {
console.log(3);
resolve(4);
});
const p2 = new Promise((resolve) => {
console.log(1);
setTimeout(() => {
console.log(6)
}, 0);
resolve(2);
});
p1.then((res) => {
console.log(res)
});
p2.then((res) => {
console.log(res)
});
console.log(5);
- 整体代码作为宏任务进入主线程,先执行打印'hello world'
- 然后
p1
中打印'3',resolve(4)
在then
函数中分发到微任务事件队列 - 然后进入
p2
中打印'1',遇到setTimeout
,将其回调函数注册分发到宏任务事件队列 resolve(2)
在then
函数中分发到微任务事件队列;向下执行,再打印'5'- 第一次循环的宏任务执行完,查看微任务事件队列,先打印'4',再打印'2'
- 第二次循环,执行宏任务中的
setTimeout
,打印'6' - 结果:hello world,3,1,5,4,2,6
例子三
console.log('1');
setTimeout(function first () {
console.log('2');
setTimeout(function third () {
new Promise(function(resolve) {
console.log('3');
resolve();
}).then(function() {
console.log('4')
})
})
})
new Promise(function(resolve) {
console.log('5');
resolve();
}).then(function() {
console.log('6')
})
setTimeout(function second () {
console.log('7');
new Promise(function(resolve) {
console.log('8');
resolve();
}).then(function() {
console.log('9')
})
})
- 整体代码作为第一次宏任务,进入主线程执行,先打印'1',再将
setTimeout
的回调函数first
注册分发到宏任务事件队列 - 向下执行,进入
Promise
中打印'5',then
函数分发到微任务事件队列 - 再遇到一个
setTimeout
,将其回调函数second
注册分发到宏任务事件队列中 - 第一次循环的宏任务完成,执行微任务的
then
函数,打印'6' - 开始第二次循环,执行宏任务队列中的
first
函数打印'2';然后又遇到了setTimeout
函数,将third
函数注册分发到宏任务事件队列中(下次循环才会调用) - 接着,执行本次宏任务队列中的
second
函数打印'7',进入promise
打印'8',then
函数注册分发到微任务事件队列 - 第二次循环的宏任务完成,执行微任务的
then
函数,打印'9' - 开始第三次循环,执行宏任务队列中
third
函数,先打印'3',再执行then
中打印'4' - 结果:1,5,6,2,7,8,9,3,4
总结
- 所有的同步任务都在主线程上执行,形成一个执行栈
- 主线程之外,还存在一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件
- 一旦执行栈中所有同步任务执行完毕,系统就会读取任务队列中的事件,异步任务结束等待状态,进入执行栈,开始执行
- 重复上一步(事件轮循——重复读取主线程和任务队列中的事件)
在js中的任务做更精确的定义:
- macro-task(宏任务): 整体代码js,setTimeout,setInterval
- micro-task(微任务): Promise.then,process.nextTick(node.js)
- 在本次循环执行中,先执行宏任务,再执行微任务,都完成后,开始第二轮循环,执行宏任务,执行微任务,直到没有宏任务,完成执行
- 图片来源
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。