const pro = new Promise((resolve, reject) => {
const innerpro = new Promise((r, reject) => {
setTimeout(() => {
r(1);
});
console.log(2);
r(3);
});
resolve(4);
innerpro.then((res) => console.log(res));
console.log('yideng');
})
pro.then((res) => console.log(res));
console.log('end');
- 执行结果:
2
yideng
end
3
4
- pro中的函数体
打印 2 yideng与console.log('end')打印 end同步执行完后,才会执行pro.then()微任务的结果。 - pro.then()与innerpro.then()是微任务,内部微任务会先执行
打印 3,再执行外部微任务打印 4 - setTimeout 是宏任务,执行完以上同步任务与微任务后,就会执行setTimeout结果,由于setTimeout 内容是执行 innerpro.then()的结果,而 innerpro.then()在第一次执行完后就被释放,因此没有
打印 1
- 同步任务结果:2 yiding end
- 微任务结果:3 4
- 宏任务结果:innerpro被释放无法再次执行
- 要点:
- Promise函数中resolve的位置没有决定性,只有执行完函数体中的内容后,才会执行Promise.then()的结果,Promise.then()是微任务,函数体中内容执行完后才会执行。
setTimeout(() => {
console.log(1);
}, 0);
setImmediate(() => {
console.log(2);
});
- 结果可能是
1 2,也可能是2 1 - 原因解释:
- setTimeout(fn, 0)和 setTimeout(fn, 1)是等价的:
- Node.js中最小延迟时间是
1ms - 即使设置为0,也会被强制设置为
1ms
- Node.js中最小延迟时间是
- setImmediate是在当前轮询阶段结束后执行
- 会在
I/O事件回调之后执行 - 但在
setTimeout和setImmediate之前执行
- 会在
- 执行顺序取决于进入事件循环时的时机:
- 若进入事件循环时已经超过了
1ms,setTimeout会先执行 - 若进入事件循环时还不到
1ms,setImmediate会先执行
- 若进入事件循环时已经超过了
- setTimeout(fn, 0)和 setTimeout(fn, 1)是等价的:
- Node.js事件循环的阶段顺序:
- timers(setTimeout/setInterval回调)
- pending callbacks
- idle,prepare
- poll(I/O回调)
- check(setImmediate回调)
- close callbacks
若想保证执行顺序,最好的方式是将它们放在I/O操作会调中:
// 在I/O操作的回调中,setImmediate 总是先于 setTimeout执行
fs.readFile('file.txt', ()=>{
setTimeout(()=>{
console.log(1);
}, 0);
setImmediate(()=>{
console.log(2);
})
});
// 该情况下,一定是先打印 2,再打印 1
- 因为在I/O操作回调中,代码是在poll阶段执行的,接下来一定是先进入check阶段(执行setImmediate),然后才会进入timers阶段(执行setTimeout)。
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
});
Promise.resolve()
.then(() => {
console.log(4);
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
-
打印顺序是:
1 4 2 5 3 6 -
两个独立的Promise链,它们会交替执行
-
执行过程:
- 第一个Promise.resolve()创建一个已完成的Promise
- 第二个Promise.resolve()创建第二个已完成的Promise
- 两个Promise链的第一个then都被加入微任务队列
- 执行第一个链的第一个then,打印
1 - 执行第二个链的第一个then,打印
4 - 第一个链的第二个then被加入队列
- 第二个链的第二个then被加入队列
- 依此类推~~~
-
关键点:
- 每个.then()都会返回一个新的Promise
- 每个.then()的回调都是一个新的微任务
- 两个Promise链会交替执行,因为它们是同时启动的
- 每个链中的顺序是确定的(1-2-3 和 4-5-6)
-
总结:
- 该交替执行模式展示了Promise的并发特性,虽然都是微任务,但多个Promise链可交替执行,而不是一个链完全执行完再执行另一个链。
-
若想改变执行顺序,让第一个链完全执行完再执行第二个链
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
Promise.resolve()
.then(() => {
console.log(4);
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
});
// 输出:1, 2, 3, 4, 5, 6
eventLoop运行
console.log("1");
setTimeout(function () {
console.log("2");
process.nextTick(function () {
console.log("3");
});
new Promise(function (resolve) {
console.log("4");
resolve();
}).then(function () {
console.log("5");
});
}, 0);
process.nextTick(function () {
console.log("6");
});
new Promise(function (resolve) {
console.log("7");
resolve();
}).then(function () {
console.log("8");
});
setTimeout(function () {
console.log("9");
process.nextTick(function () {
console.log("10");
});
new Promise(function (resolve) {
console.log("11");
resolve();
}).then(function () {
console.log("12");
});
}, 0);
//process.nextTick 是微任务,优先级高于Promise
//node 11版本前 下 1 7 6 8 2 4 9 11 3 10 5 12 宏任务执行完后,会把当前队列中所有的微任务先执行,在执行下一轮宏任务 process.nextTick > Promise
//js 或11版本之后 1 7 6 8 2 4 3 5 9 11 10 12 会把当前宏任务中的微任务优先执行,也就是局部宏任务中的微任务全部执行完,才执行下一个宏任务
promise执行顺序
async function testSometing() {
console.log("#testSometing");
// 在await后面的代码会加入微任务队列,等待执行。等同于Promise.resolve("testSometing")
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
}
test();
var promise = new Promise((resolve) => {
console.log("promise start...");
resolve("promise");
});
promise.then((val) => console.log(val));
console.log("test end...");
// 在await后面的代码会加入微任务队列,等待执行。
// test start...
// #testSometing
// promise start...
// test end...
// testSometing
// 执行testAsync
// promise
// hello async
// testSometing hello async
promise执行顺序2
// 定义第一个异步函数 async1
async function async1() {
console.log("async1 start"); // 打印 async1 开始
await async2(); // 等待 async2 执行完成
console.log("async1 end"); // 打印 async1 结束
}
// 定义第二个异步函数 async2
async function async2() {
console.log("async2"); // 打印 async2
// 使用 setTimeout 创建一个宏任务,延时 0ms
setTimeout(function () {
console.log("setTimeout"); // 打印 setTimeout
}, 0);
}
// console.log('script start'); // 这行代码在图片中被注释掉了,可以选择取消注释
// 打印脚本开始
// 调用 async1 函数
async1();
// 创建一个新的 Promise
new Promise(function (resolve) {
console.log("promise1"); // 打印 promise1
resolve(); // 解析 Promise
}).then(function () {
console.log("promise2"); // 打印 promise2
});
// async 函数会阻塞当前的同步代码,直到异步操作完成,然后返回结果。
// await 会阻塞当前的同步代码,直到异步操作完成,然后返回结果。
// async1 start
// async2
// promise1
// async1 end
// promise2
// setTimeout
test.1
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
//1 7 8 2 4 5 9 11 12 因为微任务包裹在宏任务里面 需要等待宏任务执行完之后在执行其他宏任务
test.2
setTimeout(function(){
console.log(2);
},0);
new Promise(function(resolve){
console.log(3);
resolve();
console.log(4);
}).then(function(){
console.log(5);
});
console.log(6);
console.log(8);
//3 4 6 8 5 2