• 【面试题】说说你对 async和await 理解


     前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

     表妹一键制作自己的五星红旗国庆头像,超好看

    async await详解

    原理:

    async声明该函数是异步的,且该函数会返回一个promise。

    await必须放在async函数中使用

    • await+Promise

      这是最常见的场景,await 会等待Promise的状态改为fullfilled,如果成功,那么会将async函数剩余任务推入到微任务队列,如果失败,那么剩余任务不会被推入微任务队列执行,它会返回Promise.reject(err)

    • await + 普通的值

      即使await右边非函数,只是一个普通的数值,但它本质上是将其转化为 Promise.resolve(2),所以会返回一个成功的promise

      因此,当await等待到了成功的结果后,它会将async函数剩余内容推入到微任务队列中等待执行。

      1. async function run() {
      2. console.log('start 1')
      3. const res = await 2
      4. console.log(res)
      5. console.log('end')
      6. }
      7. run()
      8. console.log('3')

      image-20230925153232909

    • await+函数

    一个最简单的场景:

    1. function fn() {
    2. console.log('fn start')
    3. console.log('fn end')
    4. }
    5. async function run() {
    6. console.log('start 1')
    7. const res = await fn()
    8. console.log(res)
    9. console.log('end')
    10. }
    11. run()
    12. console.log('3')

    运行结果为:

    image-20230925154135052

    结论:如果await 右边是一个函数,它会立刻执行这个函数,而且只有当这个函数执行结束后(即函数完成)!才会将async剩余任务推入微任务队列

    image-20230925154401107

     

    image-20230925154409457

    **这是因为await等待的永远是promise,如果函数返回undefined,那么await会等待函数执行完成,将返回值转化为Promise.resolve(undefined) **(即第二种情况 await + 普通值)。如果函数执行完成后,返回一个失败的promise,那么它将不会再把剩余任务推入到微任务队列。

    复杂点的案例,如果fn函数里面嵌套了await

    案例:

    1. async function async1() {
    2. console.log(1)
    3. await async2()
    4. console.log(2)
    5. }
    6. const async2 = async () => {
    7. await setTimeout((_) => {
    8. Promise.resolve().then((_) => {
    9. console.log(3)
    10. })
    11. console.log(4)
    12. }, 0)
    13. }
    14. const async3 = async () => {
    15. Promise.resolve().then(() => {
    16. console.log(6)
    17. })
    18. }
    19. async1()
    20. console.log(7)
    21. async3()

    分析:

    • 首先调用async1 输出1 ,await async2()立刻调用async2(),直至async2函数完成后,才会将cl(2)推入微任务队列

    • 调用async2(), await 定时器,(定时器本身也是个函数),因此先将定时器的回调函数推入宏任务队列,定时器本身返回一个定时器ID

      因此,async2可以转化为:

      1. async ()=>{
      2. await 数值; //即第二种情况
      3. }

      重点:await 数值会转化为await Promise.resolve(数值),再将async函数中剩余任务推入到微任务队列执行。这时候,async2函数中的剩余任务还有个return undefined,这代表async2函数并不能立刻执行完毕,会将return undefined推入到微任务队列中(这才代表着async2函数真正执行结束)

    目前:宏任务队列:定时器回调函数任务

    ​ 微任务队列:return undefined(async2函数执行完毕)

    • 回到开始,await async2(),目前async2还没有执行结束,因此调用cl(7)
    • 调用async3(),微任务队列推入 cl(6)

    目前:宏任务队列:定时器回调函数任务

    ​ 微任务队列:return undefined(async2函数执行完毕) cl(6)

    • 从微任务队列中取出第一个任务,return undefinedasync2()函数执行完毕,await async2() 转化为 Promise.resolve(undefined),因此将cl(2) 推入微任务队列

    所以真正的结果是:1 7 6 2 4 3

    image-20230925161025826

    案例2:

    1. async function async1() {
    2. console.log(1)
    3. await async2()
    4. console.log(2)
    5. }
    6. const async2 = async () => {
    7. await (async () => {
    8. await (() => {
    9. console.log(3)
    10. })()
    11. console.log(4)
    12. })()
    13. }
    14. const async3 = async () => {
    15. Promise.resolve().then(() => {
    16. console.log(6)
    17. })
    18. }
    19. async1()
    20. console.log(7)
    21. async3()

    思路:

    • 首先跟开始一样,调用async1() 输出1,遇到await async2(),进入等待状态,等待async2()函数完成

    • 调用async2函数,遇到await 立即执行函数1,立即执行立即执行函数1,又遇到了await 立即执行函数2,继续执行立即执行函数2,输出3。同时立即执行函数2没有返回值,等同于return undefined。因此可以转化为

      await Promise.resolve(undefined)
      

      等待到了成功的promise,将cl(4)和立即执行函数1的返回值结果(return undefined)即立即执行函数1完成 推入到微任务队列

    目前:宏任务队列:

    ​ 微任务队列:cl(4) return undefined(即立即执行函数1完成)

    • 因为async2函数内部 await 立即执行函数1,所以它需要等待立即执行函数1完成后,将async2函数执行完成推入微任务队列,再将cl(2)推入微任务队列

    • 输出7

    • 调用async3 ,将cl(6)推入微任务队列

    目前:宏任务队列:

    ​ 微任务队列:cl(4) return undefined(即立即执行函数1完成) cl(6)

    • 同步任务完成,调用微任务队列任务,输出4,立即执行函数1完成,将async2完成推入微任务队列,将cl(2)推入微任务队列。

    目前:宏任务队列:

    ​ 微任务队列: cl(6) async2完成 cl(2)

    所以最后的结果是:1 3 7 4 6 2。

    image-20230925162429385

     

     前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

     表妹一键制作自己的五星红旗国庆头像,超好看

  • 相关阅读:
    float单精度浮点数如何在计算机中存储
    搭建PXE服务器安装UEFI启动的centos7
    Spring Boot 接口数据加解密,so easy!
    web前端期末大作业——仿小米商城电商平台(6页) html+css+javascript网页设计实例 企业网站制作
    一文进阶什么是负载均衡,通俗易懂的全文解析
    快来试试!免费用上GPT-4 !!!
    Word控件Spire.Doc 【页面设置】教程(3):在 C#、VB.NET 中设置 Word 页边距
    HTML5+CSS3+JS小实例:始终飞向鼠标的纸飞机
    金仓数据库 KingbaseES 插件参考手册 K (1)
    Codeforces Round #803 (Div. 2) D. Fixed Point Guessing
  • 原文地址:https://blog.csdn.net/weixin_42981560/article/details/133316467