为什么此代码在执行微任务后不会触发渲染?
它会,否则您将看不到正在更新的文本...
也许您无法从开发工具中分辨出来?
这是可能,因为现在通常将鼠标事件限制在屏幕刷新率,这意味着,当分派鼠标事件的任务将运行时,您已经在绘画框中,这可能是为了其他原因(据我所知,mousemove事件是通过这种方式限制的,而不是click ...)。因此,在执行Promise callback will get executed步骤之前,您的update the rendering是同步的(只有第六步“将currentTask设置为null”),然后所有的开发工具都将看到一个正常的绘制框架,就像以前一样期待。因此maybe,开发工具在这里不会显示任何特殊之处,但是鉴于您的主张范围很广,很难指出一个特定的原因,这只是我的理论。
您可以尝试通过从此类事件内部调用requestAnimationFrame
来验证该理论,并检查它是否在同一事件循环迭代中执行:
onclick = (evt) => {
console.clear();
setTimeout( () => console.log( 'timeout' ), 0 );
requestAnimationFrame( () => console.log( 'rAF' ) );
};
Click anywhere<br>
If "rAF" gets logged before "timeout", the click event got handled in a painting frame.
对我来说,它经常在Chrome中运行,而在Firefox中仅偶尔运行一次,但是与此同时,我知道Chrome's rAF is broken ...因此,这一理论非常薄弱。
为什么在计时器之前执行后消息?
这取决于User-Agent(浏览器)以及何时执行此代码以使该语句为true,当然还取决于这样做的原因。
[In Chrome,他们将传递给setTimeout
的超时值设置为最少1ms:
base::TimeDelta interval_milliseconds =
std::max(base::TimeDelta::FromMilliseconds(1), interval);
<< [message任务没有超时,因此将立即排队。因此,如果没有其他任务要处理,那么它将是下一个执行的任务,距离1ms超时还没有解决。
[In Firefox,他们将由setTimeout
安排的任务视为低优先级,从页面加载安排时的任务”(这意味着在Firefox中,消息任务实际上会在setTimeout
以后触发)是在页面加载后安排的:
function test() {
setTimeout(function setTimeout1() {
console.log('setTimeout1')
}, 0)
var channel = new MessageChannel();
channel.port1.onmessage = function onmessage1() {
console.log('postMessage');
Promise.resolve().then(function promise1() {
console.log('promise1');
})
};
channel.port2.postMessage(0);
setTimeout(function setTimeout2() {
console.log('setTimeout2')
}, 0);
console.log('sync');
}
console.log( 'testing @ page load' );
test();
setTimeout(() => {
console.log( 'testing after page load' );
test();
}, 1000 );
/* results in Firefox:
testing @ page load
sync
postMessage
promise1
setTimeout1
setTimeout2
testing after page load
sync
setTimeout1
setTimeout2
postMessage
promise1
*/
但是这些是实现上的怪癖,规范中没有任何东西可以使这种行为形式化。