1.async
带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。
例如:
async function fn(){
return "hello";
}
let foo = fn();
console.log(foo);
运行结果:
Promise {<fulfilled>: "hello"}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "hello"
等同于:
function fn(){
return new Promise((resolve => {
resolve("hello");
}))
}
let foo = fn();
console.log(foo);
2.await await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。
//语法
[return_value] = await expression; //注意,返回并不是一个Promise对象,而是结果
遇到await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,继续执行await后面的代码。
例如:
async function fn(){
setTimeout(() => console.log("delay task running... "), 2000);
return "success";
}
async function test() {
let foo = await fn("success"); //返回的是结果
console.log(foo);
}
test();
console.log("ending now....");
运行结果:
ending now....
success
delay task running...
如果上例改写如下:
async function fn(){
setTimeout(() => console.log("delay task running... "), 2000);
return "success";
}
async function test() {
let foo = fn("success"); //返回的是Promise对象;
console.log(foo);
}
test();
console.log("ending now....");
运行结果:
Promise {<fulfilled>: "success"}__proto__: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: "success"
ending now....
delay task running...
async最大的好处是解决了 then 多层回调。
假设:假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
async function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
//Promise方案
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
运行结果:
step1 with 300
step2 with 500
step3 with 700
result is 900
doIt: 1503.097900390625 ms
async 改写如下:
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
async function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
//async 写法
//对比 promise写法,
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
运行效果相同。我们发现 async 函数完美的解决了then的多重调用问题。流程清晰,直观、语义明显。