翼度科技»论坛 编程开发 JavaScript 查看内容

JS事件循环机制(面试快速解题技巧)

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
目录

事件循环机制

同步与异步

我们先思考两个问题,如下:
为什么会存在同步和异步的概念?
我们的JavaScript是单线程的,也就是我们的工作流水线的只有一条。如果我们的任务全放在流水线上,其中一个任务出现问题就会阻塞后面的任务,导致我们的工作流水线卡住。因此为了更加高效合理利用这条流水线,在JavaScript中出现了同步与异步的概念。
同步与异步任务如何在一条流水线上工作?
同样是一条流水线。我们的有不同的产品,有的产品能瞬间完成,有的产品需要耗费大量时间才能完成。那么我们给这堆产品分为两类,能瞬间完成的产品先放入流水线前面,而需要耗费大量时间的产品则放在流水线后面。将所有的产品按顺序从流水线上执行。即使后面有部分产品制作很慢,但我们流水线前面的大部分产品都能顺利完成。也就是说,我们能够及时交付大部分的产品,让老板基本满意就足够了。后面的产品我们再慢慢做也不迟。
同步
同步任务:我们的任务不会造成流水线阻塞,瞬间就能完成。那我们直接把这些任务定义为同步任务。
同步事件:new Promise()、async关键字、console对象方法
异步
异步任务:我们的任务可能会造成流水线阻塞,需要时间才能完成。那我们直接把这些任务定义为异步任务。
异步事件:我们先不介绍异步事件,因为异步事件又分为微任务与宏任务。我们下面再介绍。
微任务与宏任务(异步事件)

微任务事件:Promise.then()、await 后面的语句、queueMiscrotask、MutationObserver、process.nextTick( node.js环境 )[ 微任务中最先执行 ]
宏任务事件:setTimout() 和 setInterval()、<script>脚本、I/O、UI交互事件、setImmediate( node.js环境 )[ 宏任务中最后执行 ]
注意:异步事件分为微任务和宏任务,其中微任务优先于宏任务执行。
任务执行顺序

执行栈:同步代码会首先归类到此处待执行。按照代码的书写顺序(上到下)入栈。
微任务队列:异步中的微任务代码归类到此处。按照代码的书写顺序(上到下)入队。当执行栈为空时,微任务会出队进入执行栈
宏任务队列:异步中的宏任务代码归类到此处。按照代码的书写顺序(上到下)入队。当微任务队列为空时,宏任务会出队进入执行栈
我们采用验证法做几道题
第一道如下
  1. console.log(1)
  2. setTimeout(() => {
  3.     console.log(2)
  4.     setTimeout(() => {
  5.         console.log(3)
  6.     }, 1000)
  7. }, 1000)
  8. new Promise((resolve, reject) => {
  9.     console.log(4)
  10.     resolve(5) // 之后会调用 then 方法
  11.     console.log(6)
  12. }).then((resolve, reject) => {
  13.     console.log(resolve)
  14. })
  15. function add(a, b) {
  16.     return a + b
  17. }
  18. async function foo() {
  19.     console.log(7)
  20.     let num = await add(4, 4)
  21.     console.log(9)
  22.     return num
  23. }
  24. foo().then((num) => {
  25.     console.log(num)
  26. })
  27. console.log(10) // 1 4 6 7 10 5 9 8 2 3
复制代码
以上代码没有出现宏任务嵌套微任务,微任务嵌套宏任务的情况。那么我们可以按编号(对应的输出语句)直接对执行栈、微任务和宏任务分类如下:
第一次分析执行栈(同步任务):1 4 6 7 10
第二次分析微任务:5 9 8
第三次分析宏任务:2 3
然后我们按执行顺序将答案组合在一起。最终答案:1 4 6 7 10 5 9 8 2 3。
注意:以上分析方法只能应对异步函数无嵌套的情况。
接下来我们增加难度,宏任务嵌套微任务,微任务嵌套宏任务第二题如下
  1. console.log(1)
  2. setTimeout(() => {
  3.     console.log(2)
  4.     new Promise((resolve, reject) => {
  5.         console.log(3)
  6.               resolve(4)
  7.     }).then((resolve, reject) => {
  8.         console.log(resolve)
  9.     })
  10.           console.log(5)
  11. }, 1000)
  12. console.log(6)
  13. new Promise((resolve, reject) => {
  14.     console.log(7)
  15.     resolve(8)
  16.     setTimeout(() => {
  17.         console.log(9)
  18.     }, 1000)
  19. }).then((resolve, reject) => {
  20.     console.log(resolve)
  21. })
  22. console.log(10) // 1 6 7 10 8 2 3 5 4 9
复制代码
以上代码出现了宏任务嵌套微任务,微任务嵌套宏任务的情况。
提示:外部(全局作用域)的代码可以按任务执行顺序分析,异步函数内部其实也可以按照我们的任务执行顺序分析。其分析过程是一样的。
最终答案:1 6 7 10 8 2 3 5 4 9。还有很多特例,可自行编写异步函数测试。总结方法
最终总结

分析方法:先对代码进行事件分类,然后分别放入对应类型的三个地方(执行栈、微任务队列和宏任务队列)再按照我们的执行顺序,发生异步函数嵌套情况时,也可以对其内部应用这套规则解决。
任务执行顺序如下

  • 同步(new Promise()、async关键字、console对象方法)
  • process.nextTick(node.js环境)
  • 微任务(异步)(Promise().then()、await 后面的语句)
  • 宏任务(异步)(定时器函数、<script>脚本、I/O、UI交互事件)
  • setImmediate(node.js环境)(当前事件循环结束后执行)
参考


来源:https://www.cnblogs.com/chscript/p/16994963.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具