async/await
一、异步的实现:
1、 使用异步回调,但有callback hell (回调地狱)的风险,所以为了解决这个回调地狱的问题采用了Promise
2、Promise then catch 链式调用,但也是基于回调函数的
3、async/await 是用同步的语法来编写异步代码,彻底消灭回调函数
二、async/await 和 Promise 的关系
- async/await 是消灭异步回调的终极武器,用同步代码的方式实现异步
- async/await 和 Promise并不互斥,反而两者相辅相成
- 执行 async 函数,返回的是Promise对象
- await 相当于Promise 的then
- async/await 使用 try...catch 捕获异常;代替了Promise 的 catch
举例说明:
1. 执行 async 函数,返回的是Promise对象
async函数里面的 return 如果不是一个Promise(是一个值,或者没有返回),那么会按照return Promise.resolve(值) 处理
async function fn1(){ // return 100 //相当于 Promise.resolve(100) return Promise.resolve(200) } const res1 = fn1() //执行async 函数返回的是 Promise 对象 console.log(res1,'res1') //Promise 对象 res1.then(data=>{ console.log(data,'data') // 100 })
2. await 相当于 Promise 的 then
await 后面如果是一个值,可以看作是Promise.resolve(值)
await 返回的值相当于执行了 Promise.then。所以返回的就是 Promise.then 里面的值
async function fn1(){ return Promise.resolve(200) } !(async function (){ const p1 = Promise.resolve(300) // p1 是一个Promise 对象 const data = await p1 //await 相当于 Promise then console.log(data) // 300 })() !(async function (){ const data = await 400 // 相当于 await Promise.resolve(400) then console.log(data) // 400 })() !(async function (){ const data = await fn1() // 相当于 await Promise.resolve(200) then console.log(data) // 200 })() </script>
2.async/await 使用 try...catch 捕获异常
async 函数中使用await后,就没办法取到错误信息或者Promise.reject('信息') 返回的信息(因为上面我们知道 awiat 相当于Promise.then)。
我们可以使用try....catch 来不会异常信息,代替了Promise.reject
!(async function(){ try{ const p4 = Promise.reject('错误') // 状态为rejected 的 Promise console.log(1) let data = await p4 // await 相当于 Promise then ;此处会抛出错误进入catch中,下面的代码都不会执行 console.log(data,'22') // 此处不会执行 }catch(ex){ console.log(ex) } })()
执行结果为: 1 '错误'
三、async/await 异步本质 还是回调函数
1、上面提到async/await 是消灭异步回调的终极武器,但JS还是单线程,还是有异步的,所以还是要基于Event Loop。并不是有了async/await 就没有异步了
2、async/await只是一个语法糖,只是以同步代码的写法实现了异步
3、await 下面的代码可以看作是异步的回调函数,需要等同步代码执行完,开启event loop 把回调函数放到调用栈(call stack) 中执行
看个例子,更好地理解async await 执行过程
async function fn1(){ console.log(1) await fn2() //awiat 后面的相当于异步回调函数,需要同步执行完,再通过event loop 执行 console.log(2) await fn3() //await 后面的相当于异步回调函数 console.log(3) } async function fn2(){ console.log(4) } async function fn3(){ console.log(5) } console.log(6) fn1() console.log(7)
分析:
1. console.log(6) 输出6,然后调用fn1()
2. fn1中 第一行直接打印 1,遇到await fn2() 会立即执刑 fn2(),并且await fn2() 后面的代码相当于异步回调函数,放到了微任务队列中等待执行
3. fn2() 直接打印 4
4. 继续执行 同步代码console.log(7),打印 7
5、至此同步代码执行完,调用栈为空,开始事件循环,微任务队列里的回调函数方法放到调用栈中执行
6、执行console.log(2),输出 2;
7. 执行 await fn3() ,会立即执行fn3(),同时将后面的代码 放到微任务队列中
8. 执行 fn3(),打印 5
9、至此调用栈为空,开始进入又一次事件循环,执行微任务队列中的回调函数
10、执行 console.log(3),打印3
所以最终输出: 6 1 4 7 2 5 3