• 聊一聊JavaScript中的事件循环


    一、概念:事件循环

    JavaScript是单线程的

    1、整片 script 整体代码(第一个宏任务)放到执行栈中,执行之后,会触发很多方法

    这些方法只能一个个的顺序执行,不能并发

    2、这些要执行的方法会放到一个称之为事件队列的地方

    3、事件队列又分为宏任务队列和微任务队列,所以要执行的方法会被分类到各自类型的队列列表

    4、微任务队列的任务是最优先的,只有微任务队列的任务执行完成后,才会去宏任务队列取队头的第一个任务放到执行栈执行

    5、之后可能又产生宏任务和微任务,继续步骤4,微任务优先完成,不断循环下去直到所有任务队列的任务清空

    这是整体的一个流程


    二、分类

    下面分类介绍下:

    术语:

    1)、执行栈:用来执行当前代码

    例子:

    各个同步代码

    a()

    b()

    c()

    2)、宏任务队列:存储宏任务任务

    例子:

    script 整体代码

    setInterval

    setTimeout

    I/O

    UI 交互

    setImmediate

    3)、微任务队列:存储微任务任务

    例子:

    Promise.then

    process.nextTick

    4)、异步请求未完成挂起队列:存储异步耗时任务

    例如:未完成的 ajax 请求被挂起


    三、流程:

    浏览器解析脚本---

    解析到的同步代码按照顺序推入执行栈中---

    1、顺序执行执行栈中的所有同步代码---

    2、执行完执行栈中的所有同步代码,产生 宏任务队列 微任务队列 异步请求未完成挂起队列---

    3、此时执行栈为空

    4、查看微任务队列是否有任务?

    5、有微任务则执行!当次微任务队列全部执行完,微任务队列为空,才去查看宏任务队列

    6、没有微任务则直接查看宏任务队列是否有任务,有,取出宏任务队列最前面的任务推入执行栈---

    注:在执行微任务宏任务的过程中,异步请求未完成挂起队列中的任务可能已经完成,完成后会推入宏任务队列

    7、顺序执行执行栈中的所有同步代码---如此循环


    四、练习例子

    例子一

    // 请写出输出内容 --- 网上搜出来的一个例子
    async function async1() {
      console.log('async1 start') // 2
      await async2()
      console.log('async1 end') // 6
    }
    async function async2() {
      console.log('async2') // 3
    }
    
    console.log('script start') // 1
    
    setTimeout(function() {
      console.log('setTimeout') // 8
    }, 0)
    
    async1()
    
    new Promise(function(resolve) {
      console.log('promise1') // 4
      resolve()
    }).then(function() {
      console.log('promise2') // 7
    })
    console.log('script end') // 5
    
    // 输出结果:
    // script start
    // async1 start
    // async2
    // promise1
    // script end
    // async1 end
    // promise2
    // setTimeout
    
    解析:
    第一轮:解析整个代码片段,相当于第一个宏任务在执行栈中执行
    此时状态:
    执行栈:整片代码段
    宏任务队列:null
    微任务队列:null
    
    执行过程:
    1、遇到 console.log('script start') 直接执行
    2、遇到 setTimeout(function() {
      console.log('setTimeout')
    }, 0) 
    获得一个宏任务 
    `function() {
      console.log('setTimeout')
    }`
    3、遇到 async1(),执行后
    解析到 console.log('async1 start') 直接执行
    然后解析到 await async2()
    执行 async2() 后,遇到 console.log('async2') 直接执行
    上面执行完成后,await 之后的动作作为一个微任务 `console.log('async1 end')` 被收集
    4、遇到 new Promise
    直接执行 console.log('promise1'),然后获取一个微任务 `console.log('promise2')`
    5、最后直接执行 console.log('script end')
    
    执行后状态:
    执行栈:null
    宏任务队列: 
    `function() {
      console.log('setTimeout')
    }`
    微任务队列
    `console.log('async1 end')`
    `console.log('promise2')`
    
    
    第二轮:查看执行微任务队列,然后是宏任务队列
    此时状态(即上一轮执行后的状态):
    执行栈:null
    宏任务队列: 
    `function() {
      console.log('setTimeout')
    }`
    微任务队列
    `console.log('async1 end')`
    `console.log('promise2')`
    
    执行过程:
    1、先看微任务队列是否有任务,先清空微任务队列
    将 console.log('async1 end') 拿到执行栈执行
    执行完成后 将 console.log('promise2') 拿到执行栈执行
    执行完成,执行栈此时为空
    2、此时微任务队列都执行完成了,执行栈也为空,从宏任务队列队头取第一个任务
    将 function() {
      console.log('setTimeout')
    } 拿到执行栈执行
    执行完成,所有任务都清空,程序结束
    
    

    ### 例子二 ```javascript setTimeout(() =>{ console.log(1) setTimeout(() =>console.log(2)) setTimeout(() =>console.log(3)) Promise.resolve().then(() => console.log('a')) .then(() => console.log('b')) .then(() => console.log('c')) .then(() => console.log('d')) }) // 输出结果:1 a b c d 2 3

    解析:
    1、执行整片代码,产生一个宏任务,没有微任务
    宏任务:
    () =>{ console.log(1) setTimeout(() =>console.log(2)) setTimeout(() =>console.log(3)) Promise.resolve().then(() => console.log('a')) .then(() => console.log('b')) .then(() => console.log('c')) .then(() => console.log('d')) .then(() => console.log('e')) }
    2、将宏任务拿到执行栈执行,陆续执行里面的代码
    产生两个宏任务和一个微任务
    宏任务:
    () =>console.log(2)
    () =>console.log(3)
    微任务:
    () => console.log('a')
    3、将一个微任务拿到执行栈执行
    此时又产生一个微任务
    宏任务:
    () =>console.log(2)
    () =>console.log(3)
    微任务:
    () => console.log('b')
    4、将一个微任务拿到执行栈执行
    此时又产生一个微任务
    宏任务:
    () =>console.log(2)
    () =>console.log(3)
    微任务:
    () => console.log('c')
    5、将一个微任务拿到执行栈执行
    此时又产生一个微任务
    宏任务:
    () =>console.log(2)
    () =>console.log(3)
    微任务:
    () => console.log('d')
    6、将一个微任务拿到执行栈执行
    微任务执行完成,取宏任务队列队头第一个任务
    7、执行 () =>console.log(2) 完后,没有产生微任务,取第二个任务
    8、执行 () =>console.log(3) 完后,没有任务,程序结束

    都读到最后了、留下个建议如何
  • 相关阅读:
    CUP的MESI协议
    synchronized 锁的升级
    BigDecimal/Long 前后端交互失去精度解决办法
    nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
    根据文件原始名称,文件根路径按照日期生成存储路径
    异步处理MultipartFile -- No such file or directory
    select下拉框相关操作(更新中。。。)
    input清空和重置select下拉框
    sql多字段分组排序显示全部数据
    ajax发送请求下载字节流形式的excel文件
  • 原文地址:https://www.cnblogs.com/linjunfu/p/11185776.html
Copyright © 2020-2023  润新知