async
async/await
实际上是Generator
的语法糖。顾名思义,async
关键字代表后面的函数中有异步操作,await
表示等待一个异步方法执行完成。声明异步函数只需在普通函数前面加一个关键字async
即可,如:
async function funcA() {}
async
函数返回一个Promise对象(如果指定的返回值不是Promise对象,也返回一个Promise,只不过立即 resolve
,处理方式同 then
方法),因此 async
函数通过 return
返回的值,会成为 then
方法中回调函数的参数:
async function funcA() {
return 'hello!';
}
funcA().then(value => {
console.log(value);
})
// hello!
单独一个 async
函数,其实与Promise执行的功能是一样的,接下里让我们看看 await
都干了些啥。
await
顾名思义, await
就是异步等待,它等待的是一个Promise,因此 await
后面应该写一个Promise对象,如果不是Promise对象,那么会被转成一个立即 resolve
的Promise。 async
函数被调用后就立即执行,但是一旦遇到 await
就会先返回,等到异步操作执行完成,再接着执行函数体内后面的语句。总结一下就是:async
函数调用不会造成代码的阻塞,但是await
会引起async
函数内部代码的阻塞。看看下面这个例子:
async function func() {
console.log('async function is running!');
const num1 = await 200;
console.log(`num1 is ${num1}`);
const num2 = await num1+ 100;
console.log(`num2 is ${num2}`);
const num3 = await num2 + 100;
console.log(`num3 is ${num3}`);
}
func();
console.log('run me before await!');
// async function is running!
// run me before await!
// num1 is 200
// num2 is 300
// num3 is 400
可以看出调用 async func
函数后,它会立即执行,首先输出了'async function is running!'
,接着遇到了 await
异步等待,函数返回,先执行func()
后面的同步任务,同步任务执行完后,接着await等待的位置继续往下执行。可以说,async
函数完全可以看作多个异步操作,包装成的一个Promise 对象,而await
命令就是内部then
命令的语法糖。
值得注意的是, await
后面的 Promise 对象不总是返回 resolved
状态,只要一个 await
后面的Promise状态变为 rejected
,整个 async
函数都会中断执行,为了保存错误的位置和错误信息,我们需要用 try...catch
语句来封装多个 await
过程,如下:
async function func() {
try {
const num1 = await 200;
console.log(`num1 is ${num1}`);
const num2 = await Promise.reject('num2 is wrong!');
console.log(`num2 is ${num2}`);
const num3 = await num2 + 100;
console.log(`num3 is ${num3}`);
} catch (error) {
console.log(error);
}
}
func();
// num1 is 200
// 出错了
// num2 is wrong!
如上所示,在 num2
处 await
得到了一个状态为 rejected
的Promise对象,该错误会被传递到 catch
语句中,这样我们就可以定位错误发生的位置。
async/await比Promise强在哪儿?
接下来我们用async/await
改写一下Promise章节中关于sayHi
的一个例子,代码如下:
function sayHi(name) {
return new Promise((resolved, rejected) => {
setTimeout(() => {
resolved(name);
}, 2000)
})
}
async function sayHi_async(name) {
const sayHi_1 = await sayHi(name)
console.log(`你好, ${sayHi_1}`)
const sayHi_2 = await sayHi('李四')
console.log(`你好, ${sayHi_2}`)
const sayHi_3 = await sayHi('王二麻子')
console.log(`你好, ${sayHi_3}`)
}
sayHi_async('张三')
// 你好, 张三
// 你好, 李四
// 你好, 王二麻子
与之前长长的then链和then方法里的回调函数相比,这样的写法看起来像是同步写法并且更加清爽,更加符合编程习惯。