JS中的async和await
JS中的async和await
Vapaus Qi概述
async/await是ES2017引入的特性专门用来简化异步编程。async和await是JavaScript中用于处理异步操作的关键字,它们针对前端异步编程,提供了更清晰、更简洁的语法。本文将详细介绍 async/await 的使用、及个人对其的一些理解。
async/await简介
async/await 是 JavaScript 中用于处理异步代码的语法糖, async用于定义一个异步函数,而 await用于暂停异步函数的执行,直到Promise的状态变成resolved或rejected。
async:定义一个异步函数,该函数会返回一个 Promise。即使函数内部没有显式返回 Promise,async函数也会隐式将返回值包装成 Promise。
await:只能在async函数中使用,用于等待Promise返回的状态。它会暂停函数的执行,直到Promise完成,并返回Promise的结果。
1 | //async函数也会隐式将返回值包装成 Promise可以理解为如下代码: |
但需要注意的是,虽然会隐式将返回值包装成 Promise但是它和正常显式返回Promise并不是等价的,比如:
1 | const p = new Promise((res, rej) => { |
async/await使用方法
1 | // 定义一个返回 Promise 的异步函数 |
以上,我们模拟了一个异步返回数据的函数fetchData,并且在getData中使用了async/await来处理这个异步函数。这样可以在getData感觉到是同步顺序的处理数据结果。
async/await中的异常处理
async/await 中可以使用 try…catch 来处理异步操作中的错误。
1 | async function getData() { |
多个异步任务的顺行和并行
当我们需要等待多个异步任务都执行完成的时候执行某些操作的话,我们通常用Promise.all() 或 Promise.allSettled() 来处理。
1 | // 顺序执行 |
在你有多个不依赖于彼此成功完成的异步任务时,或者你总是想知道每个 promise 的结果时,使用 Promise.allSettled() 。
相比之下,如果任务相互依赖,或者如果你想在任何 promise 被拒绝时立即拒绝,Promise.all() 返回的 Promise 可能更合适。
其他
其实用法就是如上非常简单。
在查阅资料的时候,在阮一峰老师的博客中写到:ES2017 标准引入了 async 函数,使得异步操作变得更加方便。 sync 函数是什么?一句话,它就是 Generator 函数的语法糖。
这句话在我感觉可能不是特别准确。
async/await 不能简单地说是 Generator 的语法糖,它实际上是一种全新的语法和控制流机制。虽然它们在行为上有相似之处(如暂停、恢复函数执行的能力),但 async/await 和 Generator 在设计理念、实现细节和使用方式上有根本性的不同
设计理念和用途的不同
Generator:主要用于生成序列、迭代器和控制异步流。
通过 yield 暂停函数执行,并在外部调用 next() 时恢复执行。
使用起来略显复杂,需要外部控制其执行流。async/await: 专为简化异步代码的书写而设计,使其看起来像同步代码。
await 会自动等待一个 Promise 解决,并返回结果;不需要手动调用 next()。
语法简洁,易读易维护
实现机制的不同
- Generator:由 Iterator迭代器驱动,使用 next()、throw() 和 return() 方法控制。
yield 仅暂停当前执行并返回值,后续的执行需要手动控制。 - async/await:
基于 Promise,await 会等待 Promise 解决并返回结果或抛出异常。
引擎将 async 函数中的代码拆分成多个微任务,挂载到微任务队列中异步执行。
语法和执行上的差异
- Generator和 async/await 的差异不仅仅是语法,而是从根本上改变了代码的执行控制流。
- async/await 的执行是自动的,内部实现是将代码拆分成可暂停执行的微任务序列,不需要显式地控制函数的暂停和恢复。
编译器兼容处理
为了在不支持 async/await 的环境中运行,Babel 等编译器会将 async/await 转换为 Generator 和 Promise 结合的代码。这是一些编译器的实现细节。