为了账号安全,请及时绑定邮箱和手机立即绑定

事件执行顺序和渲染

事件执行顺序和渲染

白板的微信 2022-10-08 15:39:42
var con = document.getElementById('con');con.onclick = function () {  Promise.resolve().then(function Promise1() {    con.textContent = 0;    // requestAnimationFrame(() => con.textContent = 0)  });};<div id="con">this is con</div>为什么这段代码在执行微任务后不触发渲染?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');为什么 postmessage 在 timer 之前执行?
查看完整描述

1 回答

?
30秒到达战场

TA贡献1828条经验 获得超6个赞

为什么这段代码在执行微任务后不触发渲染?

确实如此,否则您将看不到正在更新的文本...

也许您无法从您的开发工具中分辨出来?

可能是因为鼠标事件现在通常被限制为屏幕刷新率,这意味着当调度鼠标事件的任务将运行时,您已经处于绘画框架中,这可能是出于其他原因(因为我知识,mousemove事件以这种方式受到限制,而不是单击...)。
因此,您的Promise 回调将同步执行(只有第六步“将 currentTask 设置为 null”),在更新渲染步骤开始之前,所有开发工具都会看到一个正常的绘画框架,就像它在期待。
所以也许,开发工具在这里不会显示任何特别的东西,但是鉴于您的主张的广泛性,很难确定一个特定的原因,这只是我的一个理论。

您可以尝试通过requestAnimationFrame从此类事件内部调用来验证该理论,并检查它是否确实在同一事件循环迭代中执行:


显示代码片段


对我来说,它在 Chrome 中经常发生,在 Firefox 中只是偶尔出现一次,但同时我知道Chrome 的 rAF 被破坏了......所以这个理论非常薄弱。


为什么 postmessage 在 timer 之前执行?

这将取决于用户代理(浏览器)以及何时执行此代码以使该语句成立,当然也取决于它这样做的原因。

在 Chrome中,他们为传递给的超时值设置了至少 1ms setTimeout

  base::TimeDelta interval_milliseconds =   
    std::max(base::TimeDelta::FromMilliseconds(1), interval);

消息任务没有超时,因此将立即排队。因此,如果没有其他任务要处理,它将是下一个执行的任务,早在 1ms 超时解决之前。

在 Firefox中,他们将调度的任务setTimeout视为低优先级,当从页面加载开始调度时(这意味着在 Firefox 中setTimeout,如果两者都在页面加载之后调度,则消息任务实际上会在一个之后触发:


显示代码片段

)。
因此,在这种页面加载的特殊情况下,他们将消息任务视为比超时任务更重要,并且任务执行者必须选择下一步执行哪个任务(作为事件第一步的一部分循环处理模型),它将在超时后选择消息。


但这些都是实现的怪癖,规范中的任何内容都没有正式化这种行为。



查看完整回答
反对 回复 2022-10-08
  • 1 回答
  • 0 关注
  • 74 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号