JavaScript 编程中,经常使用到异步交互,因为逻辑嵌套或者请求嵌套,所以出现了 许多延时、数据不同步的问题。从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又都有额外的复杂性,都需要理解抽象的底层运行机制。
async函数就是为了解决异步交互的问题而出现的。
async 函数对 Generator 函数的改进,体现在内置执行器、更好的语义及更广的适用性。
async函数的特点:
-
语义化强
-
里面的await只能在async函数中使用
-
await后面的语句可以是promise对象、数字、字符串等
-
async函数返回的是一个Promsie对象
-
await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行
函数前面的async关键字,表明该函数内部有异步操作。async也只能使用在函数前,请找对位置,不可以加到将函数赋值给某个值的最前面。
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value)
}
//指定50毫秒以后,输出"hello world"。
asyncPrint('hello world', 50);
await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。
await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。
async function dbFuc(db) {
let docs = [{}, {}, {}];
// 报错
docs.forEach(function (doc) {
await db.post(doc);
});
}
上面代码会报错,因为 await 用在普通函数之中了,该函数应该为forEach后的普通函数。但是,如果将 forEach 方法的参数改成 async 函数也是不对的。
async function dbFuc(db) {
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}
上面代码可能不会正常工作,原因是这时三个 db.post 操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
如果希望多个请求并发执行,可以使用 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);
}