ECMAScript 6及之后的几个版本逐步加大了对异步编程机制的支 持,提供了令人眼前一亮的新特性。ECMAScript 6新增了正式的 Promise (期约)引用类型,支持优雅地定义和组织异步逻辑。接 下来几个版本增加了使用 async 和 await 关键字定义异步函数的 机制。

async await

在ES6中为了解决回调的书写方式,引入了Promise的then函数,业务逻辑很多的时候,需要链式多个then函数,语义会变得很不清楚。

  1. new Promise((resolve, reject) => {this.login(resolve)})
  2. .then(() => this.getInfo())
  3. .then(() => {// do something})
  4. .catch(() => { console.log("Error") })

ES8中把async和await变得更加方便,它其实就是 Generator 以及 Promise 的语法糖。async/await是写异步代码的新方式,以前的方法有回调函数和Promise。相比于Promise,它更加简洁,并且处理错误、条件语句、获取中间值都更加方便。这些实现让一些异步任务写起来更像是执行同步任务

基本用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

只要是函数前带 async 关键词,说明这个函数一定返回一个 Promise 对象。如果 async 关键字函数返回的不是 promise,会自动用 Promise.resolve()包装;如果 async 关键字函数显式地返回 promise,那就以返回的 Promise 为主。

  1. async function fn1() {
  2. return "async1 start";
  3. }
  4. function fn2() {
  5. return "fn start";
  6. }
  7. console.log(fn1());
  8. console.log(fn2());

image.png

async 函数多种使用形式。

  1. // 函数声明
  2. async function foo() {}
  3. // 函数表达式
  4. const foo = async function () {};
  5. // 箭头函数
  6. const foo = async () => {};
  7. // 对象的方法
  8. let obj = { async foo() {} };
  9. obj.foo().then(...)
  10. // Class 的方法
  11. class Storage {
  12. constructor() {
  13. this.cachePromise = caches.open('avatars');
  14. }
  15. async getAvatar(name) {
  16. const cache = await this.cachePromise;
  17. return cache.match(`/avatars/${name}.jpg`);
  18. }
  19. }
  20. const storage = new Storage();
  21. storage.getAvatar('jake').then(…);
  1. async getData(){
  2. let res = await app.api.getRequest(`admin/orders/status?status=5&offset=1&limit=20`);
  3. console.log(res.data)
  4. this.setData({
  5. sale: res.data
  6. })
  7. }

await

await 等待表达式的等待结果的时候,分为两种情况,一种是 promise 对象;一种是非 promise 对象。

如果表达式返回的等待的结果不是 promise,await 会阻塞后边的代码执行,此时跳出 async 函数,执行外面的同步代码,所有的同步代码执行完成之后,再把返回非 promise 结果作为 await 的等待结果。

如果表达式返回的等待的结果是 promise 对象,那么 await 也会暂停 async 后续的代码,执行 async 外的同步代码。当等到 promise 执行 fulfilled,把 resolve 的参数作为 await 的返回结果。

  1. async function async1() {
  2. console.log("async1 start");
  3. await async2();
  4. console.log("async1 end");
  5. }
  6. async function async2() {
  7. console.log("async2");
  8. }
  9. async1();
  10. console.log("script start");

image.png

Top-level Await

在ES2017中,引入了 async 函数和 await 关键字,以简化 Promise 的使用,但是 await 关键字只能在 async 函数内部使用。尝试在异步函数之外使用 await 就会报错:SyntaxError - SyntaxError: await is only valid in async function。

ES2022 顶层 await 允许我们在 async 函数外面使用 await 关键字。它允许模块充当大型异步函数,通过顶层 await,这些 ECMAScript 模块可以等待资源加载。这样其他导入这些模块的模块在执行代码之前要等待资源加载完再去执行。