zoukankan      html  css  js  c++  java
  • js的事件循环机制和任务队列

    上篇讲异步的时候,提到了同步队列和异步队列的说法,其实只是一种形象的称呼,分别代表主线程中的任务和任务队列中的任务,那么此篇我们就来详细探讨这两者。

    一、来张图感受一下

    如果看完觉得一脸懵逼,请继续往下看。

    二、解析

    我们还是拿上篇的例子做解析

    step1:f1、Promise对象实例化、f2被放入主线程的堆内存中;

    step2:Promise对象实例化后的同步代码块被放入主线程的执行栈中执行,并且产生的异步任务被放入任务队列;

    step3:f1被放入主线程的执行栈中执行(打印“我是F1”),for循环产生的1000个定时器(异步任务)放入任务队列;

    step4:f2被放入主线程的执行栈中执行,连续5次;

    step5:至此,主线程的执行栈中已经没有任务了,于是事件循环(event loop)机制从任务队列中取出一个任务放入主线程的执行栈中执行;

    step6:等待主线程的执行栈中又没有任务了,事件循环机制再次去任务队列中取出任务;

    step7:重复第6步。

     三、任务队列

    上面提到了任务队列,任务队列就是等候执行的一系列任务,就好比锅里的饭,你只有把碗里的饭吃完了,才能再次去锅里再盛一碗(不要杠!);

    只有主线程的执行栈中没有了任务,事件循环机制才会去任务队列拿任务去执行。

    由刚开始的图,你也看到了,任务队列是分不同类别并且是有优先级的。

    • 任务队列又分为macro-task(宏任务)和micro-task(微任务);
    • macro-task大概包括:script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI rendering;
    • micro-task大概包括:process.nextTick,Promise,Object.observe(已废弃),MutationObserver(html5新特性)
    • setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的具体执行任务。
    • 来自不同任务源的任务会进入到不同的任务队列

    优先级的话,micro-task > macro-task;

    对于micro-task:process.nextTick > Promise.then

    对于macro-task:setTimeout > setImmediate

    具体的案例演示,请参照这篇文章:事件循环的顺序(优先级)
    四、简单demo带你理解事件循环
    Promise.resolve().then(()=>{
      console.log('Promise1')  
      setTimeout(()=>{
        console.log('setTimeout2')
      },0)
    })
    
    setTimeout(()=>{
      console.log('setTimeout1')
      Promise.resolve().then(()=>{
        console.log('Promise2')    
      })
    },0)

    step1:

    分析:开始任务队列里有微任务promise1和宏任务timeout1,第一次事件循环一看有微任务,二话不说,直接拿promise1到主线程跑(其实是跑完所有的微任务);promise1运行结果是,控制台打印promise1,并生成一个宏任务timeout2。

    step2:

    分析:因为此时任务队列里只有宏任务,于是,根据队列规则以及优先级(这里只有一种宏任务,所以没有涉及到优先级),事件循环拿timeout1去主线程跑;

    timeout1运行结果,打印setTimeout1,并生成一个微任务promise2,至此第一次事件循环结束。

     

    step3:

    分析:任务队列里有微任务promise2和宏任务timeout2,事件循环一看有微任务,二话不说,直接拿promise2到主线程跑;

    运行结果,控制台打印promise2,此时任务队列只剩下一个宏任务timeout2。

    step4:

    分析:此时任务队列只有一个宏任务timeout2,事件循环二话不说,因为没得挑了嘛,直接拿到主线程去跑,控制台打印timeout2,至此结束,也是第二次事件循环结束。

    所以,一次事件循环是跑完所有微任务并推一个宏任务到主线程的过程。

  • 相关阅读:
    Codeforces 787D. Legacy 线段树优化建图+最短路
    Codeforces 1051E. Vasya and Big Integers
    BZOJ3261 最大异或和
    BZOJ3531 SDOI2014 旅行
    洛谷P2468 SDOI 2010 粟粟的书架
    2018 ICPC 焦作网络赛 E.Jiu Yuan Wants to Eat
    HDU6280 From Tree to Graph
    HDU5985 Lucky Coins 概率dp
    (HDU)1334 -- Perfect Cubes (完美立方)
    (HDU)1330 -- Deck (覆盖物)
  • 原文地址:https://www.cnblogs.com/eco-just/p/10389933.html
Copyright © 2011-2022 走看看