ES6 —— async 函数
async
语法:
async function name([param[, param[, ... param]]]) { statements }
- name: 函数名称。
- param: 要传递给函数的参数的名称。
- statements: 函数体语句。
返回值
sync 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。
async function helloAsync(){
return "helloAsync";
}
console.log(helloAsync()) // Promise {<resolved>: "helloAsync"}
helloAsync().then(v=>{
console.log(v); // helloAsync
})
await
语法:
[return_value] = await expression;
- expression: 一个 Promise 对象或者任何要等待的值。
返回值
await 关键字仅在 async function 中有效。
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。
function testAwait (x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function helloAsync() {
var x = await testAwait ("hello world");
console.log(x);
}
helloAsync ();
// hello world
await针对所跟不同表达式的处理方式:
- Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
- 非 Promise 对象:直接返回对应的值。
async/awiat的使用规则:
- async 表示这是一个async函数, await只能用在async函数里面,不能单独使用
- async 返回的是一个Promise对象,await就是等待这个promise的返回结果后,再继续执行
- await 等待的是一个Promise对象,后面必须跟一个Promise对象,但是不必写then(),直接就可以得到返回值
备注:
async/await的目的为了简化使用基于 promise 的 API 时所需的语法。async/await的行为就好像搭配使用了生成器和 promise。
描述
async 函数一定会返回一个 promise 对象。如果一个 async 函数的返回值看起来不是 promise,那么它将会被隐式地包装在一个 promise 中。 如:
async function foo() {
return 1;
}
// 等价于
function foo() {
return Promise.resolve(1);
}
async 函数的函数体可以被看作是由 0 个或者多个 await 表达式分割开来的。从第一行代码直到(并包括)第一个 await 表达式(如果有的话)都是同步运行的。这样的话,一个不含 await 表达式的 async 函数是会同步运行的。然而,如果函数体内有一个 await 表达式,async 函数就一定会异步执行。如:
async function foo() {
await 1;
}
// 等价于
function foo() {
return Promise.resolve(1).then(() => undefined);
}
在 await 表达式之后的代码可以被认为是存在在链式调用的 then 回调中,多个 await 表达式都将加入链式调用的 then 回调中,返回值将作为最后一个 then 回调的返回值。
async function foo() {
const result1 = await new Promise((resolve) =>
setTimeout(() => resolve("1"))
);
const result2 = await new Promise((resolve) =>
setTimeout(() => resolve("2"))
);
}
foo();
promise 链不是一次就构建好的,相反,promise 链是分阶段构造的,因此在处理异步函数时必注意对错误函数的处理。
例如,在下面代码中,即使在 promise 链中进一步配置了 .catch 方法处理,也会抛出一个未处理的 promise 被拒绝的错误。这是因为 p2 直到控制从 p1 返回后才会连接到 promise 链。
async function foo() {
const p1 = new Promise((resolve) => setTimeout(() => resolve("1"), 1000));
const p2 = new Promise((_, reject) => setTimeout(() => reject("2"), 500));
const results = [await p1, await p2]; // 不推荐使用这种方式,请使用 Promise.all 或者 Promise.allSettled
}
foo().catch(() => {}); // 捕捉所有的错误...
示例
function resolveAfter2Seconds() {
console.log("starting slow promise");
return new Promise((resolve) => {
setTimeout(() => {
resolve("slow");
console.log("slow promise is done");
}, 2000);
});
}
function resolveAfter1Second() {
console.log("starting fast promise");
return new Promise((resolve) => {
setTimeout(() => {
resolve("fast");
console.log("fast promise is done");
}, 1000);
});
}
async function sequentialStart() {
console.log("==SEQUENTIAL START==");
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. this runs 3 seconds after 1.
}
async function concurrentStart() {
console.log("==CONCURRENT START with await==");
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second(); // starts timer immediately
// 1. Execution gets here almost instantly
console.log(await slow); // 2. this runs 2 seconds after 1.
console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
function concurrentPromise() {
console.log("==CONCURRENT START with Promise.all==");
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then(
(messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
}
);
}
async function parallel() {
console.log("==PARALLEL with await Promise.all==");
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async () => console.log(await resolveAfter2Seconds()))(),
(async () => console.log(await resolveAfter1Second()))(),
]);
}
sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast"
// wait above to finish
setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast"
// wait again
setTimeout(concurrentPromise, 7000); // same as concurrentStart
// wait again
setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow"
使用 async 函数重写 promise 链
返回 Promise的 API 将会产生一个 promise 链,它将函数肢解成许多部分。例如下面的代码:
function getProcessedData(url) {
return downloadData(url) // 返回一个 promise 对象
.catch(e => {
return downloadFallbackData(url) // 返回一个 promise 对象
})
.then(v => {
return processDataInWorker(v); // 返回一个 promise 对象
});
}
可以重写为单个 async 函数:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch (e) {
v = await downloadFallbackData(url);
}
return processDataInWorker(v);
}
在上述示例中,return 语句中没有 await 运算符,因为 async function 的返回值将被隐式地传递给Promise.resolve
持续更新……
参考