博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS事件循环,MACRO TASK,MICRO TASK
阅读量:6876 次
发布时间:2019-06-26

本文共 3499 字,大约阅读时间需要 11 分钟。

事件循环的基本概念

  • JS执行的过程中,由JS引擎控制的函数调用栈来控制时间循环
  • 定时器线程,事件触发线程,异步http请求线程控制异步的任务队列
  • 任务分为macro task,micro task 对应都有不同的任务队列
    • macro task:script正常代码,setTimeout,setInterval,I/O,UI rendering
      •   由事件触发线程维护  
    • micro task:process.nextTick,promise,mutationObserve 
      •   由JS引擎线程维护
    • 最终在函数调用栈中完成

事件循环执行的顺序

  • 执行函数调用栈中的macro task,直到调用栈清空(剩下全局)
  • 执行job queues中所有可执行的micro tasks
  • 执行UI render
  • 从事件队列中获取macro task,开始新的事件循环

例子

1
begin
// Let's get hold of those elementsvar outer = document.querySelector('.outer');var inner = document.querySelector('.inner');var i = 0;// Let's listen for attribute changes on the// outer elementnew MutationObserver(function() {    console.log('mutate');}).observe(outer, {    attributes: true});// Here's a click listener…function onClick() {    i++;    if(i === 1) {        inner.innerHTML = 'end';    }    console.log('click');    setTimeout(function() {        alert('锚点');        console.log('timeout');    }, 0);    Promise.resolve().then(function() {        console.log('promise');    });    outer.setAttribute('data-random', Math.random());}// …which we'll attach to both elementsinner.addEventListener('click', onClick);outer.addEventListener('click', onClick);

 

当我们点击 inner div 时程序依次的执行顺序是:

  1. onclick 入 JS stack
  2. 打印出 click
  3. 将 timeout 压入到 macrotask
  4. 将 promise 压入到 microtask
  5. 修改 outer 属性 data-random
  6. 将 mutate 压入到 microtask,
  7. onclick 出 JS stack

此时,由于用户点击事件onclick产生的macrotask执行完毕,JS stack 清空,开始执行microtask.

  1. promise 入 JS stack
  2. 打印出 promise
  3. promise 出 JS stack
  4. mutate 入 JS stack
  5. 打印出 mutate
  6. mutate 出 JS stack

此时,microtask 执行完毕,JS stack 清空,但是由于事件冒泡,接着执行outer上的onclick事件.

  1. onclick 入 JS stack
  2. 打印出 click
  3. 将 timeout 压入到 macrotask
  4. 将 promise 压入到 microtask
  5. 修改 outer 属性 data-random
  6. 将 mutate 压入到 microtask,
  7. onclick 出 JS stack

此时,由于outer上的onclick事件产生的macrotask执行完毕,JS stack 清空,开始执行microtask.

  1. promise 入 JS stack
  2. 打印出 promise
  3. promise 出 JS stack
  4. mutate 入 JS stack
  5. 打印出 mutate
  6. mutate 出 JS stack

此时,本轮事件循环结束,UI 开始 render.

  1. 页面中inner的innerHTML变为end

此时,UI render 完毕,开始下一轮事件循环.

  1. timeout 入 JS stack
  2. 弹出警告 锚点.
  3. 打印出 timeout
  4. timeout 出 JS stack
  5. timeout 入 JS stack
  6. 弹出警告 锚点.
  7. 打印出 timeout
  8. timeout 出 JS stack

到此为止,整个事件执行完毕,我们可以看到在弹出警告框之前inner的内容已经改变

那如果不是用户点击事件触发onclick,而是js触发呢?
inner.addEventListener('click', onClick);outer.addEventListener('click', onClick);inner.click();

此时的执行顺序是:

  1. 首先是script(整体代码)入 JS stack
  2. onclick 入 JS stack
  3. 打印出 click
  4. 将 timeout 压入到 macrotask
  5. 将 promise 压入到 microtask
  6. 修改 outer 属性 data-random
  7. 将 mutate 压入到 microtask,
  8. onclick 出 JS stack

此时,inner 的 onclick 已经出 JS stack,但是script(整体代码)还没有出 JS stack,还不能执行microtask,由于冒泡,接着执行 outer 的 onclick.

  1. onclick 入 JS stack
  2. 打印出 click
  3. 将 timeout 压入到 macrotask
  4. 将 promise 压入到 microtask
  5. 修改 outer 属性 data-random

接着执行的outer.setAttribute('data-random', Math.random());,但是由于上一个mutation microtask还处于等待状态,不能再添加mutation microtask,所以这里不会将 mutate 压入到 microtask。接着执行:

  1. onclick 出 JS stack
  2. script(整体代码)出 JS stack

此时,inner.click()执行完毕,script(整体代码)已出 JS stack,JS stack 清空,开始执行mircotask.

  1. promise 入 JS stack
  2. 打印出 promise
  3. promise 出 JS stack
  4. mutate 入 JS stack
  5. 打印出 mutate
  6. mutate 出 JS stack
  7. promise 入 JS stack
  8. 打印出 promise
  9. promise 出 JS stack

此时,所有的mircotask执行完毕,本轮事件循环结束,UI 开始 render.

  1. 页面中inner的innerHTML变为end

此时,UI render 完毕,开始下一轮事件循环.

  1. timeout 入 JS stack
  2. 弹出警告 锚点.
  3. 打印出 timeout
  4. timeout 出 JS stack
  5. timeout 入 JS stack
  6. 弹出警告 锚点.
  7. 打印出 timeout
  8. timeout 出 JS stack

到此为止,整个事件执行完毕,我们可以看到在弹出警告框之前inner的内容已经改变

 

 

参考文献:

https://segmentfault.com/a/1190000013212944

http://zhangxiang958.github.io/2018/02/03/Event%20Loop%20中的%20microtask%20与%20macrotask/

 

转载于:https://www.cnblogs.com/ninalei/p/8637981.html

你可能感兴趣的文章
(已解决!)精选30道Java笔试题解答
查看>>
【Python之旅】第七篇(三):使用Redis订阅服务
查看>>
linux远程桌面链接windows
查看>>
TrendMicro:新的APT***针对亚洲和欧洲政府组织,包括中国媒体机构
查看>>
C语言中sizeof与strlen区别2
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
UIWebView加载html网页时使用缓存和清空缓存
查看>>
我的友情链接
查看>>
设计模式学习笔记(六)之策略模式(Strategy)
查看>>
python运行spark脚本程序
查看>>
我的友情链接
查看>>
通过libvirt使用ceph块设备
查看>>
优秀交互设计师成长指南
查看>>
SDN网络系统之MiniNet的安装与使用
查看>>
java的Iterator和listIterator的区别
查看>>
服务器虚拟化的好处
查看>>
AxureRP7.0基础教程系列 部件详解 表格Tabel
查看>>
ORACLE之sql语句优化
查看>>