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

简介: 【面试题】说说你对 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函数剩余内容推入到微任务队列中等待执行。
 async function run() {
                console.log('start 1')
                const res = await 2
                console.log(res)
                console.log('end')
            }
            run()
            console.log('3')
  • await+函数

一个最简单的场景:

            function fn() {
                console.log('fn start')
                console.log('fn end')
            }
            async function run() {
                console.log('start 1')
                const res = await fn()
                console.log(res)
                console.log('end')
            }
            run()
            console.log('3')

运行结果为:

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

 

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

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

案例:

async function async1() {
    console.log(1)
    await async2()
    console.log(2)
}
const async2 = async () => {
    await setTimeout((_) => {
        Promise.resolve().then((_) => {
            console.log(3)
        })
        console.log(4)
    }, 0)
}
const async3 = async () => {
    Promise.resolve().then(() => {
        console.log(6)
    })
}
async1()
console.log(7)
async3()

分析:

  • 首先调用async1 输出1 ,await async2()立刻调用async2(),直至async2函数完成后,才会将cl(2)推入微任务队列
  • 调用async2(), await 定时器,(定时器本身也是个函数),因此先将定时器的回调函数推入宏任务队列,定时器本身返回一个定时器ID
    因此,async2可以转化为:
async ()=>{
  await 数值;  //即第二种情况
}
  • 重点: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

案例2:

async function async1() {
    console.log(1)
    await async2()
    console.log(2)
}
const async2 = async () => {
    await (async () => {
        await (() => {
            console.log(3)
        })()
        console.log(4)
    })()
}
const async3 = async () => {
    Promise.resolve().then(() => {
        console.log(6)
    })
}
async1()
console.log(7)
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。

 

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

地址:前端面试题库

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

相关文章
|
7月前
|
前端开发 JavaScript 开发者
No102.精选前端面试题,享受每天的挑战和学习(async/await)
No102.精选前端面试题,享受每天的挑战和学习(async/await)
|
7月前
|
前端开发 UED
【面试题】async/await 函数到底要不要加 try catch ?
【面试题】async/await 函数到底要不要加 try catch ?
|
7月前
|
JavaScript 前端开发
【面试题】在JS循环中使用await会怎么样?
【面试题】在JS循环中使用await会怎么样?
|
7月前
|
自然语言处理 前端开发
阿里面试官:如何给所有的async函数添加try/catch?
阿里面试官:如何给所有的async函数添加try/catch?
|
2月前
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
38 0
|
7月前
|
前端开发 UED
【面试题】 async/await 函数到底要不要加 try catch ?
【面试题】 async/await 函数到底要不要加 try catch ?
【面试题】 async/await 函数到底要不要加 try catch ?
|
7月前
|
前端开发 JavaScript 索引
【面试题】对async/await 的了解?
【面试题】对async/await 的了解?
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?