看到一道Js执行顺序的面试题,涉及到promise.then()后面的执行顺序的地方有点疑惑,尤其是then后面的console.log的执行顺序,首先上题目:
console.log("start");
setTimeout(() => {
console.log("setTimeout1");
}, 0);
(async function foo() {
console.log("async 1");
await asyncFunction();
console.log("async2");
})().then(console.log("foo.then"));
async function asyncFunction() {
console.log("asyncFunction");
setTimeout(() => {
console.log("setTimeout2");
}, 0);
new Promise((res) => {
console.log("promise1");
res("promise2");
}).then(console.log);
}
console.log("end");
来源:https://juejin.cn/post/7079681931662589960 第九题
最终的输出顺序是
- start
- async 1
- asyncFunction
- promise1
- foo.then
- end
- promise2
- async2
- setTimeout1
- setTimeout2
得到输出结果的时候很疑惑为什么 foo.then会在end之前输出,最开始我认为promise.then()是异步任务且应当是放入微任务队列,而console.log("end")是同步任务应当先执行,这篇文章点醒了我:blog.csdn.net/weixin_4577…
总结一下这里foo.then会在end之前输出的原因:
then方法接受两个参数(onFulfilled, onRejected),官方文档的解释是
If onFulfilled is not a function, it must be ignored.
If onRejected is not a function, it must be ignored.
也就是说如果then接受的参数不是一个函数,那么就会忽略这个then,这也是值穿透的原因
回到本题中来
(async function foo() {
console.log("async 1");
await asyncFunction();
console.log("async2");
})().then(console.log("foo.then"));
这里的then接受的参数是console.log("foo.then")。console.log本身是一个函数,而console.log("foo.then")是执行log函数并得到返回值undefined,因此then()实际接受的参数是undefined,不是函数,就会忽略这个then,所以这里会立即执行console.log("foo.then")并将返回值undefine传递给then方法,而then实际上是被忽略没有执行的。 而后面的一段代码:
new Promise((res) => {
console.log("promise1");
res("promise2");
}).then(console.log);
这里的then接受的参数是console.log。console.log本身是一个函数,所以这里的then不会被忽略,会被放入微任务队列。 这样就可以理解本题的输出顺序了。