zoukankan      html  css  js  c++  java
  • JS 宏任务与微任务

    什么是宏任务和微任务

    宏任务(macrotask )和微任务(microtask )

    macrotask 和 microtask 表示异步任务的两种分类。

    在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

    宏任务和微任务怎么区分

    宏任务包括:setTimeout setInterval Ajax DOM事件
    微任务:Promise async/await
    微任务比宏任务的执行时间要早

    异步与单线程(同步)

    异步和单线程是相辅相成的,js是一门单线程脚本语言,所以需要异步来辅助

    异步和同步的区别:

    • 异步不会阻塞程序的执行,
    • 同步会阻塞程序的执行,

    同步异步问题

     js任务需要排队顺序执行,如果一个任务耗时过长,后边一个任务也的等着,但是,假如我们需要浏览新闻,但新闻包含的超清图片加载很慢,总不能网页一直卡着直到图片完全出来,所以将任务设计成了两类

    • 异步任务,
    • 同步任务

    当我们打开网站时,网页的渲染过程就是一大堆同步任务,像页面骨架和页面元素的渲染,而加载图片、音乐之类的任务就是异步任务,看一下下边导图:

    同步和异步任务分别进入不同的执行“场所”,同步进入主线程,异步进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入任务队列(Event Queue)。主线程内的任务执行完毕为空,就去任务队列(Event Queue)读取对应的函数,进入主线程执行。

    上述过程会不断重复,也就是常说的Event Loop(事件循环)。

    但是,JS异步还有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入任务队列(event queue),然后再执行微任务,将微任务放入微任务队列(micro task queue),但是,这两个queue不是一个queue。当你往外拿的时候先从微任务队列里拿这个回调函数,然后再从宏任务的queue拿宏任务的回调函数,如下图:

    任务列队和event loop(事件循环)
    单线程就意味着,所有的任务都要排队,前一个结束,才会执行后面的任务。如果列队是因为计算量大,CPU忙不过来,倒也算了。但是更多的时候,CPU是闲置的,因为IO设备处理得很慢,例如
    ajax读取网络数据。js设计者便想到,主线程完全可以不管IO设备,将其挂起,然后执行后面的任务。等后面的任务结束掉,在反过头来处理挂起的任务。

    好,我们来梳理一下:

    1)所有的同步任务都在主线程上执行,行成一个执行栈。

    2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。

    3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。

    4)重复上面三步。

    只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。

    执行顺序

    主线程上宏任务、微任务执行顺序

    console.log('---start---');//第一轮主线程
     
    setTimeout(() => {
      console.log('setTimeout');  // 将回调代码放入个宏任务队列,第二轮宏任务执行
    }, 0);
     
    new Promise((resolve, reject) => {
      console.log('---Promise第一轮微任务同步执行---');//第一轮微任务同步执行
      resolve()
    }).then(()=>{
      console.log('Promise.then实例成功回调执行'); // 将回调代码放入微任务队列,第一轮宏任务执行完后立即执行
    });
     
    console.log('---end---');//第一轮主线程结束

    执行顺序:主线程 >> 主线程上创建的微任务 >> 主线程上创建的宏任务

    宏任务中包含微任务

    // 宏任务队列 1
    setTimeout(() => {
      // 宏任务队列 2.1
      console.log('timer_1');
      setTimeout(() => {
        // 宏任务队列 3
        console.log('timer_3')
      }, 0)
      new Promise(resolve => {
        resolve()
        console.log('new promise')
      }).then(() => {
        // 微任务队列 1
        console.log('promise then')
      })
    }, 0)
     
    setTimeout(() => {
      // 宏任务队列 2.2
      console.log('timer_2')
    }, 0)
    console.log('========== Sync queue ==========')

    执行顺序:主线程 >> 主线程上的宏任务队列1 >> 宏任务队列1中创建的微任务

      

  • 相关阅读:
    appdata文件夹有什么用途?C盘appdata可以删除吗?
    白话讲MyIsam和InnoDB的区别
    MVC&&MVP
    计算机程序的思维逻辑- 函数调用的基本原理
    猫狗收养所
    博客学习分类
    Android之操作SQLite
    总结---20160508
    对栈元素排序
    集合栈
  • 原文地址:https://www.cnblogs.com/dekui/p/14968517.html
Copyright © 2011-2022 走看看