1

事件循环(event loop) :

首先说事件队列(task queue)

事件队列是一个存储着待执行任务的队列,其中的任务严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行。
事件队列每次仅执行一个任务,在该任务执行完毕之后,再执行下一个任务。
执行栈则是一个类似于函数调用栈的运行容器,当执行栈为空时,JS 引擎便检查事件队列,如果不为空的话,事件队列便将第一个任务压入执行栈中运行。
当我们设置一个延迟函数的时候,当前脚本并不会阻塞,它只是会在浏览器的事件表中进行记录,程序会继续向下执行。 当延迟的时间结束之后,事件表会将回调函数添加至事件队列中,事件队列拿到了任务过后便将任务压入执行栈(stack)当中,执行栈执行任务

  • 事件循环机制:
检查事件队列是否为空,如果为空,则继续检查;如不为空,则执行 2;
取出事件队列的首部,压入执行栈;
执行任务
检查执行栈,如果执行栈为空,则跳回第 1 步;如不为空,则继续检查;

结合 Web APIs 事件循环:

  1. ajax 请求挂起,然后继续执行后面的代码,至于请求何时响应,对我们的程序不会有影响,甚至它可能永远也不响应,也不会使浏览器阻塞。
    而当响应成功了以后,浏览器的事件表则会将回调函数添加至事件队列中等待执行。
  2. 事件监听器的回调函数也是一个任务,当我们注册了一个事件监听器时,浏览器事件表会进行登记,当我们触发事件时,事件表便将回调函数添加至事件队列当中。
    事件循环器会不停的检查事件队列,如果不为空,则取出队首压入执行栈执行。当一个任务执行完毕之后,事件循环器又会继续不停的检查事件队列,

不过在这间,任务结束后浏览器会对页面进行渲染。这就保证了用户在浏览页面的时候不会出现页面阻塞的情况,这也使 JS 动画成为可能,同步就没动画的渐变效果了。

总结:

  • 事件队列严格按照时间先后顺序将任务压入执行栈执行;
  • 当执行栈为空时,浏览器会一直不停的检查事件队列,如果不为空,则取出第一个任务;
  • 在每一个任务结束之后,浏览器会对页面进行渲染;

- 接下来说一下不同的任务(task)之间的执行顺序问题

microtask

每一个 事件循环(event loop)都有着众多不同的任务来源(task source),这些来源能够保证其中的任务能够有序的执行。不过,在每一轮事件循环结束之后,浏览器可以自行选择将哪一个来源当中的任务加入到执行队列当中

任务Task是严格按照时间顺序 压栈和执行 的,当一个 task 执行结束后,在下一个 task 执行开始前,浏览器可以对页面进行重新渲染

  • Microtask 通常来说就是需要在当前 task 执行结束后立即执行的任务,
例如需要对一系列的任务做出回应,或者是需要异步的执行任务而又不需要分配一个新的 task,这样便可以减小一点性能的开销。microtask
任务队列是一个与 task 任务队列相互独立的队列, microtask 任务将会在每一个 task 任务执行结束之后执行。每一个
task 中产生的 microtask 都将会添加到 microtask 队列中, microtask 中产生的 microtask
将会添加至当前队列的尾部,并且 microtask 会按序的处理完队列中的所有任务。 microtask 类型的任务目前包括了
MutationObserver 以及 Promise 的回调函数。 microtask 执行在当前 task 结束之后,下一个 task 开始之前。
microtask 执行在当前 task 结束之后,下一个 task 开始之前。

另外补充一下上文说到的 Mutation Observer
使用链接见文章: https://segmentfault.com/a/11...

Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。
它等待所有脚本任务完成后,才会运行(即异步触发方式)。
它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。
它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。
observe方法用来启动监听,它接受两个参数。
第一个参数:所要观察的 DOM 节点
第二个参数:一个配置对象,指定所要观察的特定变动



总结:
  

  • microtask 和 task 一样严格按照时间先后顺序执行。   
  • microtask 类型的任务包括 Promise callback和 Mutation callback。
  • 当 JS 执行栈为空时,便生成一个 microtask 检查点。

最后 概括一些分类

macrotask:  
script (整体代码),setTimeout, setInterval, setImmediate, I/O, UI rendering. 
microtask:  
process.nextTick, Promise(原生),Object.observe,MutationObserver

在microtask中  process.nextTick 优先级高于 Promise。 

对于任务名称的事件队列关系

task queue == macrotask queue != microtask queue

2000exists
5 声望2 粉丝