javascript - 事件循环、Promise 和 setTimeout
问题描述
考虑以下代码。我不太明白为什么它会这样工作。
- 当代码第一次运行时,它会遇到
setTimeout
,因此它会在 Web API(或其他地方)中注册它 - 然后它看到了希望并做同样的工作
- 然后它遇到了阻塞主线程2秒的while循环
- 然而,当这个 while 循环被执行时,Promise 已经被解析并放置在微任务队列中。同样,计时器已过期并放置在宏任务(回调)队列中。所以当 while 循环完成时,我们已经准备好执行 promise 和 timer。
我知道微任务队列具有更高的优先级,应该在宏任务队列的回调之前执行,但事实并非如此。请解释原因。
setTimeout(() => {
console.log("Timer");
}, 1000);
let p = new Promise(res => {
setTimeout(() => {
res("Promise");
}, 1500);
});
p.then(msg => console.log(msg));
let start = new Date().getTime();
let stop = start;
while (stop !== start + 2000){
stop = new Date().getTime();
}
解决方案
链条的强度取决于其最薄弱的环节
你的第二个setTimeout
确实在你期望的时候开始了,但是直到 JS 去寻找它是否已经完成,它才能正式完成。查找 setTimeout 是否已完成的过程正式是一个macrotask
. 承诺解决方案(之后)是一项微任务。
因此,要解决该承诺需要发生两件事:由 JS 审查的 setTimeout 计时器,以及要解决的承诺。前者是您的情况的瓶颈。
setTimeout(() => {
console.log("Timer");
}, 1000);
let p = new Promise(res => {
setTimeout(() => {
res("Promise");
}, 1500);
console.log("setTimeout #2 has begun ticking")
});
p.then(msg => console.log(msg));
let start = new Date().getTime();
let stop = start;
while (stop !== start + 2000){
stop = new Date().getTime();
}
我们通过缩短第二个setTimeout的时间来测试一下
setTimeout(() => {
console.log("Timer");
}, 1000);
let p = new Promise(res => {
setTimeout(() => {
res("Promise");
}, 500);
console.log("setTimeout #2 has begun ticking")
});
p.then(msg => console.log(msg));
let start = new Date().getTime();
let stop = start;
while (stop !== start + 2000){
stop = new Date().getTime();
}
第二个程序在“Timer!”之前打印了“Promise”。
推荐阅读
- java - 有没有办法每 x 秒刷新一次 webView?
- php - 从 laravel auth 注销时出现错误
- nosql - 不知道对象键的 Cosmos DB 查询
- css - 如何为所有动画的子元素设置不同的动画延迟?
- python - 在行中查找带有时间戳的持续时间和列元素的总和,直到行中的某个 order_id(python)
- php - 获取日期值时,字段“日期”没有默认值
- django - 如何在 Django 模板中处理动态添加的变量
- sql - 扩大日期范围
- java - 尝试在 Java 中编译和运行示例模块时出错
- javascript - 将 jQuery 从 1.12.3 迁移到最新的 3.5.1