头图

事件循环

JavaScript 语言的一大特点就是单线程,为了主线程的畅通,EVENT LOOP 方案应运而生

前置知识点

  1. JS 有同步任务和异步任务两种
  2. 同步任务都在主线程上执行,形成一个同步任务执行栈
  3. 主线程之外,事件触发线程管理着一个任务队列,当异步任务有了运行结果,就往任务队列之中推入一个 task
  4. 当执行栈中的同步任务执行完毕,JS 引擎就会读取任务队列并将可运行的异步任务添加到执行栈中,开始执行

任务队列 [Task Queue]

事件循环是通过任务队列的机制来进行协调的,在一个事件循环中,可能有一个或者多个任务队列,一个任务队列便是一个有序任务(task)的集合

在事件循环中,每次循环操作成为 Tick,每个 Tick 的任务处理模型是比较复杂的,但是关键步骤【运行机制】大致如下:

  1. 执行一个宏任务(栈中没有就从事件队列中获取),例如:script
  2. 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  3. 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(先进先执行)
  4. 当前宏任务&微任务队列执行完毕,开始检查渲染,然后 GUI 线程接管渲染
  5. 渲染完毕后,JS 线程继续接管,开始下一个宏任务(从事件队列中获取)【重复上述步骤】

参考示例图:

 title=

宏任务[Macrotask]
可以理解为:每次执行栈执行的代码就是一个宏任务

浏览器为了使宏任务与 DOM 任务能够有序的执行,在两次宏任务之间,会对页面进行一次更新渲染 render!

此处可以思考一下是不是为了在操作 dom 的时候可以取到正确的数据,etc...

宏任务有哪些:

  1. script(整体代码)
  2. setTimeout
  3. setInterval
  4. UI 交互事件
  5. I/O
  6. postMessage
  7. MessageChannel
  8. setImmediate(Node.js)

微任务[Microtask]

可以理解为:在当前的 task 执行结束后立即执行的任务。也就是说,在当前 task 执行栈之后,下一个 task 之前,在渲染之前

思考一下:在一个宏任务执行完后,会将该任务执行期间产生的所有微任务都执行完毕(在渲染前),再去渲染,再执行下一个宏任务?

Promise 的说明

Promise 的处理程序.then、.catch、.finally 都是异步的,即便一个 promise 立即 resolve,处理程序也需要等宏任务执行完才会执行。其实 ECMA 标准规定了一个内部队列 PromiseJobs,通常称之为"微任务队列",Promise 的处理程序会被放入到该队列中,当 JS 引擎执行完当前的代码,才会从微任务队列获取任务并执行。

微任务有哪些:

  1. Promise
  2. async/await
  3. Object.observe
  4. MutationObserver
  5. process.nextTick(Node.js)

思考一下下面这个程序的输出:

 title=

参考文档

事件循环:微任务和宏任务


Durant
0 声望0 粉丝

长期and价值


下一篇 »
CSS之BFC