12. ES6 async/await 的使用

博主简介:知名前端工程师!
出没地点:重庆-沙坪坝
2022年目标:成为一个大佬
✒️ 最近在做的事情:学习「web前端开发」!———————————————————————————————————————————
版权声明:本文为 CSDN 博主「Lady Marry」的原创文章,转载请附上原文出处链接及本声明。

文章目录

  • 一. async 函数
    • 1. 概述
    • 2. 基本用法
  • 二. await 命令
    • 1. 基本用法
    • 2. 错误处理
    • 3. 多个请求并发
    • 4. 顶层 await
  • 三. 综合案例

一. async 函数

1. 概述

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 和 await 是用来处理异步操作的,把异步变为同步的一种方法。async/await 的目的为了简化使用基于 promise 的 API 时所需的语法。async/await 的行为就好像搭配使用了生成器和 promise。

如果这些文字理论看不出来 async/await 有啥用,可以直接看最后的综合案例就懂了

2. 基本用法

async函数返回一个 Promise 对象。async函数内部return语句返回的值,会成为then方法回调函数的参数。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log('resolve', v),
  e => console.log('reject', e)
)
//reject Error: 出错了

async 函数有多种使用形式。

// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jake').then();

// 箭头函数
const foo = async () => {};

二. await 命令

1. 基本用法

正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

async function f() {
  // 等同于
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123

await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

async function f() {
  return await Promise.reject('出错了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了

任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world

另一种方法是await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。

async function f() {
  await Promise.reject('出错了')
    .catch(e => console.log(e));
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// 出错了
// hello world

2. 错误处理

如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('出错了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了

防止出错的方法,也是将其放在try...catch代码块之中。

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出错了');
    });
  } catch(e) {
  }
  return await('hello world');
}

如果有多个await命令,可以统一放在try...catch结构中。

async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}

3. 多个请求并发

如果确实希望多个请求并发执行,可以使用Promise.all方法

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

// 或者使用下面的写法
async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {
    results.push(await promise);
  }
  console.log(results);
}

4. 顶层 await

早期的语法规定是,await命令只能出现在 async 函数内部,否则都会报错。从 ES2022 开始,允许在模块的顶层独立使用await命令,它的主要目的是使用await解决模块异步加载的问题。

// import() 方法加载
const strings = await import(`/i18n/${navigator.language}`);

// 数据库操作
const connection = await dbConnector();

let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}

注意,顶层await只能用在 ES6 模块

三. 综合案例

比如我们需要按顺序获取:产品数据=>用户数据=>评论数据,该怎么写呢?

萌新

// 获取产品数据
ajax('products.json', (products) => {
    console.log('products >>>', JSON.parse(products));

    // 获取用户数据
    ajax('users.json', (users) => {
        console.log('users >>>', JSON.parse(users));

        // 获取评论数据
        ajax('comments.json', (comments) => {
            console.log('comments >>>', JSON.parse(comments));
        });
    });
});

白银

// 封装,返回一个 Promise
function requestP(url) {
    return new Promise(function(resolve, reject) {
       $.getJSON(url, (data) => {
    		iterator.next(data);
  	    });
    });
}

// 获取产品数据
requestP('products.json').then(function(products){
    console.log('products >>>', products);
});

// 获取用户数据
requestP('users.json').then(function(users){
    console.log('users >>>', users);
});

// 获取评论数据
requestP('comments.json').then(function(comments){
    console.log('comments >>>', comments);
});

白银一

// Generators
function request(url) {
  $.getJSON(url, (data) => {
    iterator.next(data);
  });
}

function *main() {
    // 获取产品数据
    let products = yield request('products.json');

    // 获取用户数据
    let users = yield request('users.json');

    // 获取评论数据
    let comments = yield request('comments.json');

    console.log('products >>>', products);
    console.log('users >>>', users);
    console.log('comments >>>', comments);
}

var iterator = main();
iterator.next();

黄金

// 封装 Ajax,返回一个 Promise
function requestP(url) {
    return new Promise(function(resolve, reject) {
        ajax(url, (response) => {
            resolve(JSON.parse(response));
        });
    });
}

(async () => {
    // 获取产品数据
    let products = await requestP('products.json');

     // 获取用户数据
    let users = await requestP('users.json');

     // 获取评论数据
    let comments = await requestP('comments.json');

    console.log('ES7 Async/products >>>', products);
    console.log('ES7 Async/users >>>', users);
    console.log('ES7 Async/comments >>>', comments);
}());

你可能感兴趣的:(ECMAScript,es6,javascript,前端,开发语言)