2021-01-13 00:13:57
深入理解 await 与 async
一、基本概念
async 函数:
async 函数是一个返回 Promise 对象的函数。
在函数内部,你可以使用 await 关键字来等待一个 Promise 的结果。
await 关键字:
await 关键字只能在 async 函数内部使用。
它会暂停当前 async 函数的执行,直到等待的 Promise 完成,并返回 Promise 的结果。
二、错误处理
使用 try/catch 结构:
在使用 await 时,如果遇到 Promise 被拒绝(即出错),可以使用 try/catch 结构来捕获错误。
try/catch 在 async/await 中的作用与在同步代码中的作用类似,用于捕获异常并处理。
处理多个 await 调用中的并发错误:
如果需要同时等待多个 Promise,并希望在其中一个 Promise 失败时立即处理错误,可以使用 Promise.all()。
Promise.all() 会返回一个 Promise,该 Promise 在所有传入的 Promise 都成功完成时才会完成;如果其中一个 Promise 被拒绝,则立即被拒绝,并可以通过 try/catch 捕获错误。
三、并发性
并发执行多个 await 操作:
使用 Promise.all() 可以并发执行多个 Promise,并在所有 Promise 都完成时返回结果。
Promise.allSettled() 也是用于并发执行多个 Promise 的方法,但它会在所有 Promise 都完成(无论是成功还是失败)时返回结果。
Promise.all() 和 Promise.race() 的作用:
Promise.all() 允许你并发等待多个 Promise,并返回一个在所有 Promise 都完成时完成的 Promise。
Promise.race() 返回一个 Promise,该 Promise 在第一个传入的 Promise 完成(无论是成功还是失败)时就会完成。
四、与 Promise 的关系
async/await 提供了一种更简洁、更直观的方式来处理 Promise。
在 async 函数中返回一个值,等价于调用 Promise.resolve()。
在 async 函数中抛出错误,等价于调用 Promise.reject()。
五、执行顺序
包含多个 await 语句的 async 函数的执行顺序:
函数会从顶部开始执行,当遇到第一个 await 语句时暂停,直到该 Promise 完成。
然后,函数会继续执行,直到遇到下一个 await 或函数结束。
何时使用 await 和何时避免使用:
当你需要按顺序执行异步操作时,使用 await。
当你可以并发执行多个操作时,使用 Promise.all() 或其他类似的方法,以避免不必要的等待。
六、错误和陷阱
常见错误或陷阱:
忘记使用 await,导致异步操作没有按预期等待。
在非 async 函数内部使用 await,导致语法错误。
在循环中不正确地使用 await,导致不必要的顺序执行,影响性能。
未处理的异步错误,可能导致程序崩溃或不稳定。
避免“忘记 await”的问题:
使用 TypeScript 或 ESLint 这样的工具,它们可以检测并提示你忘记使用 await 的情况。
七、实际应用
这需要根据具体的代码片段来决定,通常是将基于 Promise 的回调地狱转换为更简洁的 async/await 代码。
八、浏览器和 Node.js 支持
支持情况:
Node.js 从 7.6.0 版本开始支持 async/await。
大多数现代浏览器都支持 async/await,但旧版本的浏览器可能不支持。
在不支持的环境中使用:
可以使用 Babel 或 TypeScript 这样的转译器,将 async/await 代码转换为 ES5 或 ES6 JavaScript,以在不支持的环境中运行。
九、性能和最佳实践
性能差异:
在大多数情况下,async/await 与纯 Promises 的性能差异是可以忽略的。
但 async/await 可能会带来一些额外的运行时开销,特别是在大量异步操作的情况下。
何时使用:
当你需要更简洁和可读的代码时,使用 async/await。
对于复杂的异步逻辑或需要更细粒度控制的场景,使用 Promises。
十、其他特性和提议
async iterators 和 for-await-of:
async iterators 是一种可以异步生成值的迭代器。
for-await-of 是一种循环结构,允许你等待 async iterator 的每个值,从而简化异步迭代操作。
顶级 await:
顶级 await 是一个提议,允许你在模块的顶级使用 await,而不是仅在 async 函数中。
这可以简化模块间的异步依赖管理。