1-1.await
await
的意思就是等待。它后面可以跟一个表达式。如果是值(如字符串、数字、普通对象等等)的话,返回值就是本身的值。- 不过最常用的是后面跟一个
promise
对象。await
会等待这个promise
的状态由pending
转为fulfilled
或者rejected
。在此期间它会阻塞,延迟执行await语句后面的语句。 - 如果
promise
对象的结果是resolve
,它会将resolve
的值,作为await
表达式的运算结果。
语法糖本质
其实await
与async
本身就是promise
化编程的一种语法糖。对比一下两种写法。
// 异步promise化的函数--模拟请求后端接口function asyncFn () { return new Promise(function (resolve, reject) { setTimeout(function () { if (true) { console.log('resolve console') resolve('resolve return') } else { reject('reject return') } }, 2000) })}// promiseasyncFn().then((res) => { console.log(res)}, (err) => { console.log(err)})// awaittry { var res = await asyncFn() console.log(res)} catch(err) { console.log(err)}// 如果有第二次请求的话,promise需要在then方法继续调用,再用then接受,过多的嵌套依然会增加阅读难度。而await async只需要像写同步代码一样继续书写就可以,它是解决异步编程回调地狱的终极手段。
例一
// ps:由于js本身现在已经限制了await必须用在async函数中,否则会报错。所以请将下面的复制粘贴到浏览器控制台查看结果function asyncFn () { return new Promise(function (resolve, reject) { setTimeout(function () { if (true) { console.log('resolve console') resolve('resolve return') } else { reject('reject return') } }, 2000) })}var value1 = await asyncFn()var value2 = await 'plain text'console.log(value1)console.log(value2)//浏览器会依次打印 ‘resolve console’ ‘resolve return’ ‘plain text’
例二
如果你对结果有疑问,可以将asyncFn前面的await去掉,再在浏览器控制台执行一次。
这两次对比一下,会发现第二次的resolve console
是最后打印出来的,而第一次的是第一个打印的。
根本原因就是第一次代码中await
阻塞了后面语句的执行,等待promise
确定结果后继续执行后面语句。
例三
根据前两例可想而知,如果两个await
的后面跟着的都是promise
对象。那么第二个await等待的时间是它本身等待的时间加上第一个await
等待的时间
function asyncFn1 () { return new Promise(function (resolve, reject) { setTimeout(function () { if (true) { console.log('resolve console1') resolve('resolve return1') } else { reject('reject return1') } }, 2000) })}function asyncFn2 () { return new Promise(function (resolve, reject) { setTimeout(function () { if (true) { console.log('resolve console2') resolve('resolve return2') } else { reject('reject return2') } }, 2000) })}var value1 = await asyncFn1()var value2 = await asyncFn2()// 复制并执行,会发现2s后打印了‘resolve console1’,4s后打印了‘resolve console2’
思考
// 已经知道了await会阻塞代码的执行,如果我们在实际开发中有这样的代码。function fn () { // 假设request是请求后端接口 var value = await request() console.log(value) // ...}fn()var arr = []arr.push('1')// ...其他不依赖后端接口逻辑
在fn调用后,由于await
的阻塞,必然会影响到下面的逻辑。在实际开发中,如果后端接口5s才响应,那么下面的代码就需要等待5s。显然这是不合理的,为了解决这种现象,就需要async
声明。
1-2.async
之前我们知道了await
会阻塞代码的执行。而解决这个弊端的手段就是async
声明。
async function asyncFn () { return 'async'}console.log(asyncFn())
控制台打印一下,会发现打印的是一个promise
对象。而且是Promise.resolve
对象。resolve
的值就是asyncFn
的函数返回值async
。
如果函数没有返回值的话,它自然返回的会是Promise.resolve(undefined)
。
其实之所以async
声明能解决await
的阻塞问题,就是因为async
声明将函数作了一层promise
包装,这样内部的异步操作其实就是由pending
转为resolve
或者reject
的过程。这样函数本身就能够随意调用,函数内部的await
也不会再影响到函数外部的代码执行。