Skip to main content

event loop 机制

二、事件循环与帧

事件循环和上面 4 个名词的基本概念在此不再啰嗦了,我们着重看下它们之间的关系。浏览器是一个 UI 系统,所有的操作最终都会以页面的形式展现,而页面的基本单位是帧。一帧中可能包括的任务有下面几种类型。

  • events: 点击事件、键盘事件、滚动事件等
  • macro: 宏任务,如 setTimeout
  • micro: 微任务,如 Promise
  • rAF: requestAnimationFrame
  • Layout: CSS 计算,页面布局
  • Paint: 页面绘制
  • rIC: requestIdleCallback

Event Loop 是什么?

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。 (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 (4)主线程不断重复上面的第三步。

JavaScript的事件分两种,宏任务(macro-task)和微任务(micro-task) ● 宏任务:包括整体代码script,setTimeout,setInterval ● 微任务:Promise.then(非new Promise),process.nextTick(node中) ● 事件的执行顺序,是先执行宏任务,然后执行微任务,这个是基础,任务可以有同步任务和异步任务,同步的进入主线程,异步的进入Event Table并注册函数,异步事件完成后,会将回调函数放入Event Queue中(宏任务和微任务是不同的Event Queue),同步任务执行完成后,会从Event Queue中读取事件放入主线程执行,回调函数中可能还会包含不同的任务,因此会循环执行上述操作。

宏任务(macrotask) 微任务(microtask) 谁发起的 宿主(Node、浏览器) JS引擎 具体事件 1. script (可以理解为外层同步代码)2. setTimeout/setInterval3. UI rendering/UI事件4. postMessage,MessageChannel5. setImmediate,I/O(Node.js) 1. Promise2. MutaionObserver3. Object.observe(已废弃;Proxy 对象替代)4. process.nextTick(Node.js) 谁先运行 后运行 先运行 会触发新一轮Tick吗 会 不会

宏任务

浏览器 Node

I/O ✅ ✅ setTimeout ✅ ✅ setInterval ✅ ✅ setImmediate ❌ ✅ requestAnimationFrame ✅ ❌ 微任务

浏览器 Node

process.nextTick ❌ ✅ MutationObserver ✅ ❌ Promise.then catch finally ✅ ✅

参考