美文网首页
js EventLoop、宏任务和微任务

js EventLoop、宏任务和微任务

作者: 咸鱼不咸_123 | 来源:发表于2022-04-06 14:40 被阅读0次

    1.javascript是单线程的语言

    javascript是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。

    如下:如果有多个任务要执行,执行其他任务时,其他任务都要进行等待

    52.png

    1.1 单线程执行任务队列的问题

    如果前一个任务非常耗时,则后续的任务不得不一直等待,从而导致程序假死的问题。

    2.同步任务和异步任务

    为了防止某个耗时任务导致程序假死的问题,javascript把待执行的任务分为了两类。

    • 同步任务
      • 又叫做 非耗时任务,指的是在主线程上排队执行的那些任务
      • 只有前一个任务执行完毕,才能执行后一个任务
    • 异步任务
      • 又叫做非耗时任务,异步任务由javascript委托给宿主环境进行执行
      • 当异步任务执行完成之后,会通知javascript主线程执行异步任务的回调函数

    2.1 同步任务和异步任务的执行过程

    53.png
    • 同步任务由javascript主线程次序执行
    • 异步任务委托给宿主环境执行
    • 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
    • javascript主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行。
    • javascript主线程不断重复上面的第4步

    js的主线程会从自己的执行栈中去执行栈中的所有任务,当发现任务是同步任务时,js会自己进行执行。如果是异步任务,会委托给宿主环境执行。当js发现自己的执行栈中被执行完后,会从任务队列中按顺序把对应的回调函数取出来放入栈中,按顺序执行。

    3.EventLoop的基本概念

    javascript主线程从“任务队列”中读取异步任务回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为EventLoop(事件循环)。

    3.1 结合EventLoop分析输出顺序

    import thenFs from "then-fs";
    
    console.log("A");
    thenFs.readFile("./studyPrommise/files/1.txt","utf8").then(res=>{console.log("B");})
    
    
    setTimeout(()=>{
      console.log("C");
    },0)
    
    console.log("D");
    
    • 最终的结果是 A D C B
    • 因为主线程上只有A和D,是同步任务,所以会依次执行,而B、C是异步任务让js委托给宿主环境执行。
    • 然后定时器,只是延时了0秒,所以就会让宿主环境立即执行,然后返回一个回调函数,等主线程空闲时执行。

    4.宏任务和微任务

    javascript对异步任务又做了进一步的划分,分为了两类,

    1. 宏任务(macrotask)
      • 异步Ajax请求
      • setTimeOut、setInterval
      • 文件操作
      • 其他宏任务
    2. 微任务(microtask)
      • Promise.then、.catch、和.finally
      • process.nextTick
      • 其他微任务
    54.png

    4.1 宏任务和微任务的执行顺序

    55.png
    • 每个宏任务执行完后,都会检查是否存在待执行的微任务
    • 如果有,则会将所有待执行的微任务执行完,再执行下一个宏任务
    • 宏任务和微任务是交替执行的

    4.2 根据宏任务和微任务分析代码输出的顺序

    setTimeout(()=>{
      console.log(1);
    })
    
    new Promise(function(resolve){
      console.log(2);
      resolve()
    }).then(res=>{
      console.log(3);
    })
    
    console.log(4);
    

    最后的结果是 2 4 3 1

    • setTimeout是一个宏任务,
    • new Promise()是一个同步任务,.then()是一个微任务
    • console.log(4)是一个同步任务

    所以执行的顺序是:执行的准则是 先执行同步任务,再去任务队列中读取回调函数放入执行栈中,按次序执行。但异步任务中:先执行微任务,再执行宏任务

    1. new Promise()操作
    2. console.log(4)
    3. .then()
    4. setTimeout

    4.3 经典面试题

    56.png

    先来分析同步任务和异步任务,最后来分析异步任务中的宏任务和微任务

    • 第1行是同步任务1
    • 第3-10行是异步任务1(宏任务)
    • 第12-15行是同步任务2,也就是new Promise()这一部分
    • 第15-17行是异步任务2(微任务)
    • 第20-28行是异步任务3(宏任务)

    所以执行顺序是:同步任务js本身自身处理,而异步任务交给宿主环境执行

    js本身处理的过程:

    • 执行同步任务1 :输出1
    • 执行同步任务2:输出 5
    • 同步任务执行完
    • 从任务队列中取出执行完对应的回调函数,放入执行栈中,依次执行

    宿主环境处理的过程

    • 先执行异步任务2,执行异步任务2,并返回到任务队列中,待主线程执行 输出 6
    • 看是否存在待执行的微任务,发现没有,按次序执行宏任务
    • 先执行 异步任务1 ,并返回到任务队列中,待主线程执行输出 2 3 4
    • 在执行异步任务3 并返回到任务队列中,待主线程执行输出 7 8 9

    所以总的输出结果是: 1 5 6 2 3 4 7 8 9

    5.总结

    EventLoop和宏任务和微任务.png

    相关文章

      网友评论

          本文标题:js EventLoop、宏任务和微任务

          本文链接:https://www.haomeiwen.com/subject/ycirsrtx.html