问题描述
代码片段:
console.log('out1');
setTimeout(() => console.log('out2'),0);
Promise.resolve('out3').then(console.log);
console.log('out4');
执行后我得到以下内容:
"out1"
"out4"
"out3"
"out2"
根据我的理解,由于第 2 行和第 3 行都是异步的,所以应该先打印 out2,因为它首先被放入队列。 但这里似乎相反。
"out1"
"out4"
"out2"
"out3"
JSBin 链接:https://jsbin.com/fafipezine/edit?js,console
解决方法
您可以通过在 setTimeout
函数中解析 promise 来实现此目的:
console.log('out1');
new Promise((res) => {
setTimeout(() => {
console.log('out2');
res("out3");
},0);
}).then(console.log);
console.log('out4');
您可以在 Javascript 中阅读有关这些行为的 EventLoop。
,要回答您的问题,我们需要阐明 javascript 如何执行代码。 Javascript 跟随 run to completion model,这几乎意味着您的代码无论如何都会到达 out4 控制台日志(如果您在代码中使用 async await 或发生同步错误等,则例外) Javascript使用单线程模型,那么它是如何处理代码执行的呢? 关注你的第一个问题,我们需要看看任务队列和微任务队列是如何运作的。 这些队列基本上是为事件循环提供要做的事情。那么,它们以什么顺序被消耗?事件循环通过首先执行当前任务来消耗消息,然后继续执行可能引入的所有微任务等等(check the tasks vs microtasks topic)。 那么,什么是任务,什么是微任务? 每次请求运行代码、调用 setTimeout 或 setInterval 或触发事件(例如用户输入事件)时都会创建一个 task microtask 与任务非常相似,但它们的创建方式不同。 Promises are basically using microtasks
要回答问题的第一部分,有两个任务。第一个任务是运行这个脚本。排队的第二个任务是触发 setTimeout 的回调。在这两个任务之间,有两个 Promise(微任务)排队。以上所有结果都与您看到的打印顺序有关。 this 博文中对上述内容进行了很好的可视化,我强烈建议您阅读。
根据您的第二个问题,then function 可以使用函数引用作为参数