一、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