Skip to content

事件循环到绘制 ​

本节用一次点击同时安排同步日志、微任务和下一帧回调,观察事件循环到绘制前的顺序。

html
<button id="run">运行</button><script>
  document.querySelector('#run').addEventListener('click', () => {
    console.log('event')
    queueMicrotask(() => console.log('microtask'))
    requestAnimationFrame(() => console.log('rAF'))
  })
</script>

预期 event → microtask → rAF;把 requestAnimationFrame 换成 setTimeout(0) 后只比较调度信号,不把它当作绘制完成通知。

机制拆解 ​

同步事件处理结束后,微任务先清空,requestAnimationFrame 再提供下一帧绘制前的回调;setTimeout 只是任务调度,不保证紧邻绘制。实验要记录同一次输入中的日志顺序。

边界与失败路径 ​

  • 所有权:监听器、observer、worker、连接、缓存和焦点都有创建者与释放时机;页面隐藏、路由离开和元素移除时都要验证。
  • 宿主差异:SSR、Web Worker、Shadow DOM、跨文档、跨源和辅助技术不会共享同一套全局对象与事件路径。
  • 错误分类:取消、超时、权限拒绝、协议错误、配额不足和浏览器不支持应分别进入可观察状态。
  • 安全边界:用户输入、URL、HTML、消息和持久化数据不能仅因为来自同源或类型正确就视为可信。

可运行实验 ​

点击按钮 20 次,记录 event → microtask → rAF 的日志;再加入 60ms 同步循环,比较 Performance 面板中长任务与帧延迟。

实验记录要包含运行时、输入步骤、预期输出、实际日志和未覆盖的宿主差异。

练习 ​

  1. 记录一次点击的 event、microtask、rAF 顺序,并写出预期序列。
  2. 加入 60ms 同步循环,比较长任务和帧延迟。
  3. 说明 setTimeout 不能作为绘制完成的可靠信号。 查看本节答案

下一步 ​

完成练习后回到本章概览,按下一篇继续;遇到跨章节故障,先回到本节的所有权与宿主边界。

用心记录每一步成长