jsconst a = new Promise((res) => { setTimeout(res); }); a.then(() => { console.log(1); }) .then(() => { console.log(2); }) .then(() => { console.log(3); }); a.then(() => { console.log(4); }) .then(() => { console.log(5); }) .then(() => { console.log(6); }); setTimeout(() => { console.log(7); Promise.resolve().then(() => { console.log(8); }); }); setTimeout(() => { console.log(9); }); Promise.resolve().then(() => { console.log(10); }); console.log(11);
process.nextTick
和 setImmediate
,这两个玩意就得好好说说了。process.nextTick
process.nextTick
的性质和 Promise 一模一样,只不过 node 中的 process.nextTick
所在的任务队列的优先级比 Promise 所在的任务队列的优先级高!process.nextTick
,就只能当老二了。process.nextTick
产生的任务为 微任务Max!微任务Max 所在的队列为 微队列Max!process.nextTick
和 Promise。jsconsole.log('start') Promise.resolve().then(() => { console.log("1"); Promise.resolve().then(() => { console.log("2"); }); }); Promise.resolve().then(() => { console.log("3"); Promise.resolve().then(() => { console.log("4"); }); }); setTimeout(() => { console.log("5"); Promise.resolve().then(() => { console.log("6"); }); }); setTimeout(() => { console.log("7"); }); console.log('end')
结果为 start,end,1,3,2,4,5,6,7。
jsconsole.log('start') process.nextTick(function () { console.log("1"); process.nextTick(function () { console.log("2"); }); }); process.nextTick(function () { console.log("3"); process.nextTick(function () { console.log("4"); }); }); setTimeout(function () { console.log("5"); process.nextTick(function () { console.log("6"); }); }); setTimeout(function () { console.log("7"); }); console.log('end')
结果为 start,end,1,3,2,4,5,6,7。
jsconsole.log('start') Promise.resolve().then(() => { console.log("1"); Promise.resolve().then(() => { console.log("2"); }); }); Promise.resolve().then(() => { console.log("3"); Promise.resolve().then(() => { console.log("4"); }); }); process.nextTick(function () { console.log("5"); process.nextTick(function () { console.log("6"); }); }); process.nextTick(function () { console.log("7"); process.nextTick(function () { console.log("8"); }); }); console.log('end')
结果为 start,end,5,7,6,8,1,3,2,4
setImmediate
setImmediate
,虽然 setImmediate
所在的也是宏队列,但是和 setTimeout 所在的不是一个宏队列,那么既然不在一起,就得有优先级的区分,那么他两个谁是大哥?我找到了下面的资料:
timers: 执行setTimeout和setInterval的回调
- pending callbacks: 执行延迟到下一个循环迭代的 I/O 回调
- idle, prepare: 仅系统内部使用
- poll: 检索新的 I/O 事件;执行与 I/O 相关的回调。事实上除了其他几个阶段处理的事情,其他几乎所有的异步都在这个阶段处理。
check: setImmediate在这里执行
- close callbacks: 一些关闭的回调函数,如:socket.on('close', …)
jssetTimeout(() => { console.log("1"); }, 0); setImmediate(() => { console.log("2"); });
2, 1
jssetTimeout(() => { console.log("1"); }, 0); setImmediate(() => { console.log("2"); });
任务 | 当前执行代码 |
---|---|
主线程 | 全局代码 |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | |
定时器的计时线程 |
任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | () => { console.log(“2”);} |
定时器的计时线程 | () => { console.log(“1”);} 等1毫秒后送入定时器宏队列 |
由于示例代码实在是太少,以至于当第二次事件循环开始时,还没有超过1毫秒,所以这时主线程去查看定时器宏队列的时候,没有发现任务,因为定时器的计时线程发现还没过1毫秒,就没把() => { console.log(“1”);} 放入定时器宏队列。
那么主线程就继续往下找,发现下面setImmediate的宏队列有任务,就拿出来第一个执行,在执行过程中,定时器的计时线程发现已经到了1毫秒,随即把 () => { console.log(“1”);} 放入定时器的宏队列,姗姗来迟。
任务 | 当前执行代码 |
---|---|
主线程 | () => { console.log(“2”);} |
微任务 | |
定时器的宏队列 | () => { console.log(“1”);} |
setImmediate的宏队列 | |
定时器的计时线程 |
执行() => { console.log(“2”);}, 此时控制台打印 2
任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | () => { console.log(“1”);} |
setImmediate的宏队列 | |
定时器的计时线程 |
任务 | 当前执行代码 |
---|---|
主线程 | () => { console.log(“1”);} |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | |
定时器的计时线程 |
执行() => { console.log(“1”);}, 此时控制台打印 1
jssetTimeout(() => { console.log("1"); }, 0); setImmediate(() => { console.log("2"); }); // 这个函数可以阻塞主线程 const syncFunc = (delay) => { const time = new Date().getTime(); while (true) { if (new Date().getTime() - time > delay) { break; } } }; // 阻塞主线程1秒的时间,这个时间内,定时器的计时线程肯定有充足的时间把 () => { console.log(“1”);} 放入定时器的宏队列 syncFunc(1000)
1, 2
js// 这个函数可以阻塞主线程 const syncFunc = (delay) => { const time = new Date().getTime(); while (true) { if (new Date().getTime() - time > delay) { break; } } }; setTimeout(() => { setTimeout(() => { console.log("1"); }); setImmediate(() => { console.log("2"); }); // 阻塞主线程1秒的时间 syncFunc(1000) });
2, 1
任务 | 当前执行代码 |
---|---|
主线程 | 全局代码 |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | |
定时器的计时线程 |
定时器的计时线程
,等待1毫秒后会被送入定时器的宏队列。任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | |
定时器的计时线程 | () => { setTimeout(() => { console.log("1");}); setImmediate(() => {console.log("2");}); syncFunc(1000) } 等1毫秒后送入定时器宏队列 |
定时器的计时线程
没有动作。定时器的计时线程
的1毫秒时间已经到了,线程内的待执行代码被放入到定时器的宏队列中。任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | () => { setTimeout(() => { console.log("1");}); setImmediate(() => {console.log("2");}); syncFunc(1000) } |
setImmediate的宏队列 | |
定时器的计时线程 |
任务 | 当前执行代码 |
---|---|
主线程 | () => { setTimeout(() => { console.log("1");}); setImmediate(() => {console.log("2");}); syncFunc(1000) } |
微任务 | |
定时器的宏队列 | |
setImmediate的宏队列 | |
定时器的计时线程 |
定时器的计时线程
,等待1毫秒后会被送入定时器的宏队列。setImmediate
是立即放入队列,那么 () => {console.log("2"); 被立即放入到 setImmediate
的宏队列。定时器的计时线程
发现已经到了1毫秒,随即把 () => { console.log(“1”);} 放入定时器的宏队列任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | () => { console.log("1");} |
setImmediate的宏队列 | () => {console.log("2");} |
定时器的计时线程 |
因为如果结束了,那么会开启第四次eventloop,回到顶部继续从微任务开始向下找,然后到定时器的宏队列,那么一定会先打印1,而不是先打印2了。
任务 | 当前执行代码 |
---|---|
主线程 | () => {console.log("2");} |
微任务 | |
定时器的宏队列 | () => { console.log("1");} |
setImmediate的宏队列 | |
定时器的计时线程 |
执行() => { console.log(“2”);}, 此时控制台打印 2
任务 | 当前执行代码 |
---|---|
主线程 | |
微任务 | |
定时器的宏队列 | () => { console.log("1");} |
setImmediate的宏队列 | |
定时器的计时线程 |
执行() => { console.log("1");}, 此时控制台打印 1
setImmediate的宏队列
在 定时器的宏队列
的后面,定时器的宏队列
执行完后产生了一个新的 setImmediate的宏队列
的任务,当 定时器的宏队列
执行完后,还要继续 setImmediate的宏队列
的执行,所以2就在1的前面打印了。jssetImmediate(() => { setTimeout(() => { console.log("1"); }); setImmediate(() => { console.log("2"); }); });