async/await执行的优先级是否高于setTimeout回调



我正在写一些代码,用户可以点击按钮,计算下一次本地可见日食的时间。

这可能是一个非常耗时的计算。因此,我用几个嵌套的异步函数编写了计算代码,将所有计算分解成小块,允许频繁执行,这样用户的web浏览器就不会在计算过程中锁定。

以下是一个关于所涉及的时间问题的非常简化的测试用例,没有天文数字的复杂性(可在CodePen上获得(:

window.CP.PenTimer.MAX_TIME_IN_LOOP_WO_EXIT = 15000;
async function workWorkWork(msg) {
return new Promise(async (resolve) => {
const start = performance.now();
while (performance.now() < start + 5000) {
await new Promise((innerResolve) => {
let t = 0;
for (let i = 0; i < 1e7; ++i) t += Math.sin(Math.random());
console.log(msg || t);
// innerResolve(); // What I thought should have been sufficient
setTimeout(innerResolve); // What I had to do instead
});
}
resolve();
});
}
let busy = false;
function doStart() {
if (busy)
return;
const button = document.getElementById('my-button');
button.innerText = 'Started';
button.style.background = 'red';
busy = true;
(async () => {
setTimeout(() => (button.innerText = 'Busy'), 1000);
workWorkWork('other work');
await workWorkWork();
busy = false;
button.innerText = 'Start';
button.style.background = 'unset';
})();
}

用户点击按钮后,我想等一秒钟后再显示繁忙指示灯。繁忙指示器是在await进行计算之前使用调用的setTimeout激活的。

令我惊讶的是,UI的响应几乎就像async/await正在阻塞代码一样。几秒钟后,整个计算完成,然后繁忙指示灯出现,为时已晚。

控制台输出表明,如果我同时启动workWorkWork的两个调用,它们的输出在web控制台中是交错的,因此每个执行实例都能适当地为另一个提供时间。

但是异步函数代码不会为调用函数之前排队的setTimeout提供任何时间。它甚至不允许DOM使用异步调用之前和setTimeout之前所做的更改进行更新。

setTimeout回调及时运行的唯一方法似乎是在我的异步函数中使用其他setTimeout调用。

我第一次遇到这个问题是在Angular代码中,我想我可能看到了Angular Zone.js疯狂的特定于Angular的问题,但我现在已经在普通的ol‘JavaScript中复制了同样的问题。

这是我应该预料到的行为吗?这有记录吗?

在谷歌上搜索各种组合——async、wait、setTimeout、Promise等的排列,会产生很多素材,不幸的是,这些素材与我在这里遇到的内容无关。

单击启动后的正确行为:

按钮变红,文本变为";已启动">
大约一秒钟后,文本变为"忙">
大约四秒钟后,红色背景消失,文本变回";开始";。

单击启动后出现错误行为,没有额外的setTimeout:

按钮不会立即更改文本或颜色
大约五秒钟后,文本将更改为";"忙";,就这样被卡住了。

已履行的承诺通过微任务队列提供,该队列在定时器事件之前处理。await执行承诺,因此它也在计时器事件之前执行。

因此,如果定时器事件和承诺实现都在等待运行它们的处理程序,那么承诺将首先得到服务。

以下是关于微任务队列或更具体地说是PromiseJobs队列的更多信息。

最新更新