zoukankan      html  css  js  c++  java
  • event loop js事件循环 microtask macrotask

    转: 原文 http://blog.csdn.net/sjn0503/article/details/76087631

    ----------------------------------------------------

    放个面试题,抛个砖:

    console.log('start')
    
    const interval = setInterval(() => {  
      console.log('setInterval')
    }, 0)
    
    setTimeout(() => {  
      console.log('setTimeout 1')
      Promise.resolve()
          .then(() => {
            console.log('promise 3')
          })
          .then(() => {
            console.log('promise 4')
          })
          .then(() => {
            setTimeout(() => {
              console.log('setTimeout 2')
              Promise.resolve()
                  .then(() => {
                    console.log('promise 5')
                  })
                  .then(() => {
                    console.log('promise 6')
                  })
                  .then(() => {
                    clearInterval(interval)
                  })
            }, 0)
          })
    }, 0)
    
    Promise.resolve()
        .then(() => {  
            console.log('promise 1')
        })
        .then(() => {
            console.log('promise 2')
        })
    

    不着急揭晓答案,先分析

    首先知晓:

    js是单线程语言

    也就是说一次就只能做一件事情。

    多数的网站不需要大量计算,程序花费的时间主要集中在磁盘 I/O 和网络 I/O 上面

    虽然SSD读取很快,但和CPU处理指令的速度比起来也不在一个数量级上,而且网络上一个数据包来回的时间更慢(注意过游戏的延迟吗)

    so: 一些cpu直接执行的任务就成了优先执行主线任务,然后需要io返回数据的任务就成了等待被执行的任务

    所以才会有同步任务(synchronous)和异步任务(asynchronous)之分

    同步任务:

    在主线程上排队执行的任务,前一个任务执行完毕,才能执行后一个任务;

    异步任务:

    不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

    总之:

    只要主线程空了,就会去读取”任务队列”,这就是JavaScript的运行机制

    Microtasks Macrotasks

    任务队列不止一个,还有 microtasks 和 macrotasks

    microtasks:

    • process.nextTick
    • promise
    • Object.observe
    • MutationObserver

    macrotasks:

    • setTimeout
    • setInterval
    • setImmediate
    • I/O
    • UI渲染

    whatwg规范:https://html.spec.whatwg.org/multipage/webappapis.html#task-queue

    • 一个事件循环(event loop)会有一个或多个任务队列(task queue)
    • task queue 就是 macrotask queue
    • 每一个 event loop 都有一个 microtask queue
    • task queue == macrotask queue != microtask queue
    • 一个任务 task 可以放入 macrotask queue 也可以放入 microtask queue 中

    理解了这些定义之后,再看执行原理:

    事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次从macro-task开始,找到其中一个任务队列执行完毕,然后再执行所有的micro-task,这样一直循环下去。

    还要注意一点:

    包裹在一个 script 标签中的js代码也是一个 task 确切说是 macrotask。

    所以文首面试题的答案为:

    start 
    promise 1 
    promise 2 
    setInterval 
    setTimeout 1 
    promise 3 
    promise 4 
    setInterval 
    setTimeout 2 
    promise 5 
    promise 6

    简单来讲,整体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环至结束.

    --------------------------------------------------------2017年11月14日21:35:17---------------------------------------------------------------

    另外,这篇文章也不错

    这个知识点。。。

    https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

    前端基础进阶系列

    这个系统也超屌!!

    http://www.jianshu.com/p/cd3fee40ef59

    =======================

    Macrotask 和 microtask 都是属于上述的异步任务中的一种,我们先看一下他们分别是哪些 API :

    • macrotaskssetTimeoutsetIntervalsetImmediate, I/O, UI rendering
    • microtasksprocess.nextTickPromisesObject.observe(废弃), MutationObserver

    任务队列分为 macrotasks 和 microtasks,而Promise中的then方法的函数会被推入 microtasks 队列,而setTimeout的任务会被推入 macrotasks 队列。在每一次事件循环中,macrotask 只会提取一个执行,而 microtask 会一直提取,直到 microtasks 队列清空

    注:一般情况下,macrotask queues 我们会直接称为 task queues,只有 microtask queues 才会特别指明。

    那么也就是说如果我的某个 microtask 任务又推入了一个任务进入 microtasks 队列,那么在主线程完成该任务之后,仍然会继续运行 microtasks 任务直到任务队列耗尽。

    而事件循环每次只会入栈一个 macrotask ,主线程执行完该任务后又会先检查 microtasks 队列并完成里面的所有任务后再执行 macrotask。

    =======================

    测试代码:

    复制代码
    <script>
        console.log('script start');
        setTimeout(function() {
            console.log('setTimeout');
        },0);
        
        Promise.resolve().then(function() {
            console.log('promise');
        }).then(function() {
        console.log('promise2');
    });
    
    console.log('script end');
    
    </script>
    复制代码
  • 相关阅读:
    vue init webpack projectName命令运行报错 解决方法
    DIV实际高度小于设置高度的问题
    openlayers 地图要素的多种高亮方式 Demo(可直接运行)
    加载wkt到地图 Demo (可直接运行)
    openlayers 框选地图得到选框范围(坐标)Demo(可直接运行)
    element+vue可远程搜索可懒加载的下拉框组件
    Android-使用约束布局(ConstraintLayout)构建灵活的UI【译】
    Mysql explain 执行计划详解(转)
    Managing Hierarchical Data in MySQL(邻接表模型)[转载]
    无限极分类原理与实现(转)
  • 原文地址:https://www.cnblogs.com/oxspirt/p/7834843.html
Copyright © 2011-2022 走看看