什么是async函数?
- async是异步方案的一种
- async是Generator函数的语法糖
async与Generator的关系
- 内置执行器:Generator函数的执行必须靠执行器,而async函数自带执行器。
- 更简洁的语法:function*与yield被async和await替代。
- 返回值是Promise:Generator的返回值是Iterator对象,而async函数的返回值是Promise,除了await,你还可以使用then方法来指定下一步操作。
分别用Generator函数和async函数来实现依次读取两个文件的操作。
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函数返回一个Promise对象,可以使用then 方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
// 函数声明
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 () => {};
语法
返回Promise对象
async函数返回一个Promise对象,返回的值会成为then方法回调函数的参数。
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
)
//reject Error: 出错了
Promise对象的状态变化
async函数返回的Promise对象,必须等到内部所有await命令后面的Promise对象执行完,才会发生状态改变。除非遇到return语句或者抛出错误。只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
await命令
await命令的返回值有三种:
- Promise对象(Promise、Promise.resolve()、thenable对象、被catch的Promise.reject())
- 常量值
- 报错问题(Promise.reject()、new Error)
错误处理
await报错的问题,可以通过以下两种方式捕获处理:
- 将可能出现报错的代码放置在try...catch...块中。
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
- 通过后续的.then或.catch捕获错误。
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
await支持顶层使用
注意,顶层
await只能用在 ES6 模块,不能用在 CommonJS 模块。这是因为 CommonJS 模块的require()是同步加载,如果有顶层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');
}
// x.js
console.log("X1");
await new Promise(r => setTimeout(r, 1000));
console.log("X2");
// y.js
console.log("Y");
// z.js
import "./x.js";
import "./y.js";
console.log("Z");