ES6 async函数

一、async函数简介

1.概述

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。它就是 Generator 函数的语法糖。

2.async和Generator对比

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

//Generator函数写法
const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
//async函数写法
const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

对比发现,async函数是将Generator函数的星号(*)替换成async,将yield替换成await。

3.async函数的原理

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args) {
  // ...
}
// 等同于
function fn(args) {
  return spawn(function* () {  //spawn函数就是自动执行器
    // ...
  });
}

二、async函数用法

1.基本用法

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 () => {};

2.Promise 对象的状态变化

async函数返回的 Promise 对象,必须等到内部所有await命令后的promise执行完,才会发生状态改变,除非遇到return语句或者抛出错误。

3.await

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

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

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

4.使用注意点

1.await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}
// 另一种写法
async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}

2.多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3.async 函数可以保留运行堆栈。
函数a内部运行了一个异步任务b()。当b()运行的时候,函数a()不会中断,而是继续执行,等到b()运行结束,可能a()早就运行结束了,可以通过async来使a暂定执行,直到b()、c()完成

const a = () => {
  b().then(() => c());
};

// async使a暂停运行
const a = async () => {
  await b();
  c();
};

三、async函数应用

1.按顺序完成异步操作

依次远程读取一组 URL,然后按照读取的顺序输出结果
(1).Promise 的写法如下:

function logInOrder(urls) {
  // 远程读取所有URL
  const textPromises = urls.map(url => {
    return fetch(url).then(response => response.text());
  });

  // 按次序输出
  textPromises.reduce((chain, textPromise) => {
    return chain.then(() => textPromise)
      .then(text => console.log(text));
  }, Promise.resolve());
}

(2).async的写法

async function logInOrder(urls) {
  // 并发读取远程URL
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  // 按次序输出
  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}

https://es6.ruanyifeng.com/#docs/class

猜你喜欢

转载自blog.csdn.net/qq_41466440/article/details/110849821