async/await
介绍
继ES6
出现promise
之后,再也不用担心回调地狱,但是promise
也不是十全十美,async/await
可以让异步代码看起来就像同步的一样,这就是要学习它的原因。
首先创建一个简单的 promise:
function getData() {
return new Promise(function(resolve) {
let data = { name: "Tom" };
resolve(data);
});
}
let p = getData();
p.then(data => {
console.log(data);
return "over";
});
getData
返回一个新的promise
实例,成功resolve
之后返回data
的值,上面的写法是用ES6promise
的写法。
async function go() {
console.log(await getData());
return "over";
}
console.log(go);
go();
async
用于定义一个异步函数,该函数隐式的返回一个Promise
,该promise
的reosolve
值就是函数return
的值。(示例中reosolve
值就是字符串over
)。
await
必须在async
定义的函数中使用,当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
可以看出用async/await
写出来的代码,最明显的一点就是代码要比promise
简洁。
第二个优势,async/await
可以让try/catch
既能处理同步错误也可以处理异步产生的错误,在一般情况下使用try/catch
是不能够检测异步错误的,因为try/catch
本身就是同步的,这也就是为什么说async/await
看起来像同步的原因之一。
async function go() {
try{
console.log(JSON.parse(await getData())
return 'over'
} catch(error) {
cons
}
}
有时候可能需要嵌套异步,也就是这样:
function go() {
return promise1().then(value1 => {
return promise2(value1).then(value2 => {
return promise3(value1, value2);
});
});
}
循环嵌套看起来很让人不爽,一个解决的方法是使用promise.all
function go() {
return promise1()
.then(value1 => {
return promise.all([value1, promise2(value1)]);
})
.then((value1, value2) => {
return promise3(value1, value2);
});
}
但这样做可读性未免也太差了,而且将promise.all
本身的作用是用来将多个Promise
实例包装起来,这样直接和value1
一起使用也太奇怪了。
最好的方法是使用async/await
:
async function go() {
const value1 = await promise1();
const value2 = await promise2(value1);
return promise3(value1, value2);
}
async/await
可以让异步代码变得“同步”,但是会使异步代码不再明显,识别异步代码可能要花一些功夫。
深入理解
async
函数的返回值是一个promise
对象:
async function test() {
return "hello";
}
const a = test();
console.log(a);
返回值出乎意料,是一个promise
对象:
Promise {<resolved>: "hello"}
可以得出一个结论:async
函数返回的是一个promise
对象,如果在函数中return
一个直接量,async
会把这个值通过promise.resolve()
封装成promise
对象,如果没有返回值输出的则是Promise.resolve(undefined)
。
我们知道await
不能在async
函数外使用,所以当无法使用await
获取返回值的时候还是要用then
。
test().then(v => {
console.log(v);
});
如果没有await
,那么async
函数会立即执行,并返回一个promise
对象,这和一个返回promise
对象的普通函数没有区别。
await
等待的是一个表达式,计算结果是promise
或者其他值,await
等待的实际上是一个返回值,它可以用于任意表达式的返回结果,根据结果分两种情况:
- 如果
await
最后等到的不是一个promise
对象,那么await
的运算结果就是表达式返回的东西。 - 如果
await
最后等到的是一个promise
对象,那么他会等待promise
的状态变成resolve
,然后得到resolve
的值,作为await
表达式的运算结果。
WARNING
await
命令后面的Promise
对象,运行结果可能是rejected
,所以最好把await
命令放在try...catch
代码块中。