• 面试官:说说EventLoop事件循环、微任务、宏任务


    前言

    JS是一门单线程语言,单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行下一个任务。这样所导致的问题是:如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的觉。为了解决这个问题,JS中出现了同步和异步。他们的本质区别是:一条流水线上各个流程的执行顺序不同。在讲JS任务执行机制前,先要了解一下什么是同步任务与异步任务。

    同步任务:即主线程上的任务,按照顺序由上⾄下依次执⾏,当前⼀个任务执⾏完毕后,才能执⾏下⼀个任务。

    异步任务:不进⼊主线程,⽽是进⼊任务队列的任务,执行完毕之后会产生一个回调函数,并且通知主线程。当主线程上的任务执行完后,就会调取最早通知自己的回调函数,使其进入主线程中执行。

    1. 事件循环Event Loop概念介绍

    • 事件循环Event Loop又叫事件队列,两者是一个概念

    事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。事件循环不属于js代码本身的范畴,而是属于js编译器的范畴,在js中讨论事件循环是没有意义的。换句话说,js代码可以理解为是一个人在公司中具体做的事情, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。

    2. 微任务、宏任务概念介绍

    1. 微任务与宏任务就属于js代码的范畴
    2. js代码主要分为两大类: 同步代码、异步代码
    3. 异步代码又分为:微任务与宏任务

    01.jpg

    3. 事件循环Event Loop执行机制

    • 1.进入到script标签,就进入到了第一次事件循环.

    • 2.遇到同步代码,立即执行

    • 3.遇到宏任务,放入到宏任务队列里.

    • 4.遇到微任务,放入到微任务队列里.

    • 5.执行完所有同步代码

    • 6.执行微任务代码

    • 7.微任务代码执行完毕,本次队列清空

    • 寻找下一个宏任务,重复步骤1

      • 以此反复直到清空所以宏任务,这种不断重复的执行机制,就叫做事件循环

    画了一张图来描述事件循环

    02.jpg

    4.易错点

    (1). promise本身是一个同步的代码(只是容器),只有它后面调用的then()方法里面的回调才是微任务

    04.jpg

    (2). await右边的表达式还是会立即执行,表达式之后的代码才是微任务, await微任务可以转换成等价的promise微任务分析

    05.jpg

    (3). script标签本身是一个宏任务, 当页面出现多个script标签的时候,浏览器会把script标签作为宏任务来解析

    09.jpg

    参考 前端进阶面试题详细解答

    看到这里,对事件循环应该有所了解了,给大家看几道面试题。

    一.

    1.先执行主线程上的log(1)

    2.当有两个await时,只有第一个await右边的代码会立即执行log(4),后面的几行代码都会放入微任务队列中。

    3.执行主线程上的log(6)

    4.执行第4行至第6行的微任务

    二.

    08.jpg

    1.先执行主线程上的1,5,7

    2.主线程的同步任务执行完毕后,会先执行微任务。执行Promise的then方法里的代码,打印6

    3.微任务执行完毕后,最后执行定时器里的宏任务,打印2,3,4

    三.

    07.jpg

    1.先执行主线程上的同步代码,打印1

    2.执行第9行的函数,进⼊async1内部,async1其实是声明了⼀个promise,promise是同步代码,会顺序执⾏打印async2函数里的4 ,只有.then⾥⾯的代码会加⼊微任务队列⾥,这⾥相当于执⾏了async2()之后,再将后面的代码加⼊⼀个微任务队列中。

    3.回主线程中,遇到setTimeout(),加⼊到宏任务队列

    4.主线程继续往后执⾏,前⾯说过,promise是同步代码,.then后⾯的回调会加⼊微任务队列,所以会打印13⾏的7

    5.主线程执⾏完成,开始执⾏微任务队列内的任务,遵循先进先出的原则,打印第四⾏的2。然后接着执行第5行第二个awaite右边的代码,打印5。第6行这个时候就被加入微任务队列。

    6.接着会执行第二个微任务,也就是16行代码,打印8。第17行的then这个时候也会加入微任务队列。再依次执行第6行和第17行的两个微任务,打印3和9

    7.微任务执⾏结束,开始执⾏宏任务setTimeout,打印11⾏的6.

    总结

    1. 所有同步任务都在主线程上执行,形成一个执行栈(call stack)。
    2. 遇到异步任务, 进入异步处理模块并注册回调函数; 等到指定的事件完成(如ajax请求响应返回, setTimeout延迟到指定时间)时,异步处理模块会将这个回调函数移入异步任务队列。
    3. 当栈中的代码执行完毕,执行栈中的任务为空时,主线程会先检查微任务队列中是否有任务,如果有,就将微任务队列中的所有任务依次执行,直到微任务队列为空; 之后再检查宏任务队列中是否有任务,如果有,则取出第一个宏任务加入到执行栈中,之后再清空执行栈,检查微任务,以此循环,直到全部的任务都执行完成。
      以上就是我对JS执行原理的一些整理和理解,希望能给读者带来一些帮助。如果有理解错误或表述不当的地方,请指正。
    最后再给大家出一道题,可以把答案留在评论区

    10.jpg
    样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的觉。为了解决这个问题,JS中出现了同步和异步。他们的本质区别是:一条流水线上各个流程的执行顺序不同。在讲JS任务执行机制前,先要了解一下什么是同步任务与异步任务。

    同步任务:即主线程上的任务,按照顺序由上⾄下依次执⾏,当前⼀个任务执⾏完毕后,才能执⾏下⼀个任务。

    异步任务:不进⼊主线程,⽽是进⼊任务队列的任务,执行完毕之后会产生一个回调函数,并且通知主线程。当主线程上的任务执行完后,就会调取最早通知自己的回调函数,使其进入主线程中执行。

    1. 事件循环Event Loop概念介绍

    • 事件循环Event Loop又叫事件队列,两者是一个概念

    事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。事件循环不属于js代码本身的范畴,而是属于js编译器的范畴,在js中讨论事件循环是没有意义的。换句话说,js代码可以理解为是一个人在公司中具体做的事情, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。

    2. 微任务、宏任务概念介绍

    1. 微任务与宏任务就属于js代码的范畴
    2. js代码主要分为两大类: 同步代码、异步代码
    3. 异步代码又分为:微任务与宏任务

    01.jpg

    3. 事件循环Event Loop执行机制

    • 1.进入到script标签,就进入到了第一次事件循环.

    • 2.遇到同步代码,立即执行

    • 3.遇到宏任务,放入到宏任务队列里.

    • 4.遇到微任务,放入到微任务队列里.

    • 5.执行完所有同步代码

    • 6.执行微任务代码

    • 7.微任务代码执行完毕,本次队列清空

    • 寻找下一个宏任务,重复步骤1

      • 以此反复直到清空所以宏任务,这种不断重复的执行机制,就叫做事件循环

    画了一张图来描述事件循环

    参考 前端进阶面试题详细解答

    02.jpg

    4.易错点

    (1). promise本身是一个同步的代码(只是容器),只有它后面调用的then()方法里面的回调才是微任务

    04.jpg

    (2). await右边的表达式还是会立即执行,表达式之后的代码才是微任务, await微任务可以转换成等价的promise微任务分析

    05.jpg

    (3). script标签本身是一个宏任务, 当页面出现多个script标签的时候,浏览器会把script标签作为宏任务来解析

    09.jpg

    看到这里,对事件循环应该有所了解了,给大家看几道面试题。

    一.

    1.先执行主线程上的log(1)

    2.当有两个await时,只有第一个await右边的代码会立即执行log(4),后面的几行代码都会放入微任务队列中。

    3.执行主线程上的log(6)

    4.执行第4行至第6行的微任务

    二.

    08.jpg

    1.先执行主线程上的1,5,7

    2.主线程的同步任务执行完毕后,会先执行微任务。执行Promise的then方法里的代码,打印6

    3.微任务执行完毕后,最后执行定时器里的宏任务,打印2,3,4

    三.

    07.jpg

    1.先执行主线程上的同步代码,打印1

    2.执行第9行的函数,进⼊async1内部,async1其实是声明了⼀个promise,promise是同步代码,会顺序执⾏打印async2函数里的4 ,只有.then⾥⾯的代码会加⼊微任务队列⾥,这⾥相当于执⾏了async2()之后,再将后面的代码加⼊⼀个微任务队列中。

    3.回主线程中,遇到setTimeout(),加⼊到宏任务队列

    4.主线程继续往后执⾏,前⾯说过,promise是同步代码,.then后⾯的回调会加⼊微任务队列,所以会打印13⾏的7

    5.主线程执⾏完成,开始执⾏微任务队列内的任务,遵循先进先出的原则,打印第四⾏的2。然后接着执行第5行第二个awaite右边的代码,打印5。第6行这个时候就被加入微任务队列。

    6.接着会执行第二个微任务,也就是16行代码,打印8。第17行的then这个时候也会加入微任务队列。再依次执行第6行和第17行的两个微任务,打印3和9

    7.微任务执⾏结束,开始执⾏宏任务setTimeout,打印11⾏的6.

    总结

    1. 所有同步任务都在主线程上执行,形成一个执行栈(call stack)。
    2. 遇到异步任务, 进入异步处理模块并注册回调函数; 等到指定的事件完成(如ajax请求响应返回, setTimeout延迟到指定时间)时,异步处理模块会将这个回调函数移入异步任务队列。
    3. 当栈中的代码执行完毕,执行栈中的任务为空时,主线程会先检查微任务队列中是否有任务,如果有,就将微任务队列中的所有任务依次执行,直到微任务队列为空; 之后再检查宏任务队列中是否有任务,如果有,则取出第一个宏任务加入到执行栈中,之后再清空执行栈,检查微任务,以此循环,直到全部的任务都执行完成。
      以上就是我对JS执行原理的一些整理和理解,希望能给读者带来一些帮助。如果有理解错误或表述不当的地方,请指正。
    最后再给大家出一道题,可以把答案留在评论区

    10.jpg

  • 相关阅读:
    稳压器【TPS6283810YFPR 3A】汽车类、TPS629203QDRLRQ1,TPS74550PQWDRVRQ1采用小型6 引脚 WSON 封装。
    INTERSPEECH 2022|CALM: 基于对比学习的表现力语音合成跨模态说话风格建模【语音之家】
    讲讲项目里的仪表盘编辑器(四)分页卡和布局容器组件
    SQL注入漏洞(postgresql注入)
    html常用标签简单汇总
    OpenCV之基本绘图
    【开源】使用PhenoCV-WeedCam进行更智能、更精确的杂草管理
    AI系统ChatGPT源码+详细搭建部署教程+AI绘画系统+支持GPT4.0+Midjourney绘画+已支持OpenAI GPT全模型+国内AI全模型
    SOLIDWORKS软件提供了哪些特征造型方法?硕迪科技
    frp新版本frp_0.52.3设置
  • 原文地址:https://blog.csdn.net/loveX001/article/details/127858735