当前位置: 首页 > Web前端 > HTML

async和await其实是generator和promise的语法糖

时间:2023-03-28 17:51:44 HTML

async关键字用于声明异步函数,await用于在async函数中将异步代码变为同步代码,执行阻塞代码的朋友可以使用不熟悉promise和generator看看这些文章Promise的理解和使用(一)Promise的理解和使用(二)手写promise一步步解析Javascript事件循环机制及面试题详解async和await的推导我们用案例来介绍asyncawait关键字的作用。异步函数getRequestData的作用是等待2s返回输入函数。functiongetRequestData(data){returnnewPromise((resolve,reject)=>{setTimeout(()=>{resolve(data);},2000);});}连续调用函数3次,传入“aaa”,依次拼接“bbb”、“ccc”,最后的结果是,等待6s输出“aaabbbccc”。回调地狱实现>{console.log("result",res);});});});回调地狱式代码的可读性和可维护性都很差。为了解决这个问题,我们尝试链式调用。链调用getRequestData("aaa").then((res)=>{returngetRequestData(res+"bbb");}).then((res)=>{returngetRequestData(res+"ccc");}).then((res)=>{console.log("res",res);});通过链式调用,代码可读性稍微好一点,但是这样的代码还是不太好理解,说说它优化generatorfunction*showData(){constres1=yieldgetRequestData("aaa");constres2=yieldgetRequestData(res1+"bbb");constres3=yieldgetRequestData(res2+"ccc");console.log("res",res3);}constgenerator=showData();generator.next().value.then(res=>{generator.next(res).value.then(res=>{生成器。next(res).value.then(res=>{console.log(res)})})})使用yield将值传给函数,生成器函数中的请求代码变得简单,但是next调用好像更复杂了,还是有函数嵌套,但是有调用next方法的痕迹,可以通过递归实现。constgenerator=showData();functionexecGenerator(generator){函数exec(res){constgen=generator.next(res)if(gen.done){returngen.value}returngen.value.then(re=>{exec(re)})}exec()}execGenerator(generator)封装了下一个方法调用,异步请求变成了同步代码,可以等上一个函数执行成功后再调用下一个函数,使代码可读性更强。aysnc和await最终的async和await版本代码如下所示,其实就是generator和promise的语法糖,去掉了next方法的递归过程。异步函数showData(){constres1=awaitgetRequestData("aaa");constres2=awaitgetRequestData(res1+"bbb");constres3=awaitgetRequestData(res2+"ccc");console.log("res",res3);}showData()async函数和普通函数的区别返回值async函数也可以有返回值,它的返回值和promise一样分为三种,returnvalue是基础数据类型,会被Promise.resolve包裹,回调成功的返回值是一个promise,执行结果与promise一致。返回值是一个实现了thenable的对象,执行结果是then函数中的结果asyncfunctionfoo(){//return'hello'//returnnewPromise((resolve,reject)=>{//reject('fail')//})return{然后:(resolve,reject)=>{reject("fail");},};}constpromise=foo();promise.then((res)=>{console.log("res:",res);}).catch((err)=>{console.log("err:",err);});reject在thenable中返回,所以异步函数的结果也是reject,执行catch函数的逻辑抛出异常。普通函数抛出的异常会直接中断程序的执行,下面的代码不会执行一个异常')并且在异步函数中抛出异常,只需要定义catch方法,它是一个不会中断程序执行的异步函数foo(){thrownewError('error')}constpromise=foo();pr省略.then((res)=>{console.log("res:",res);}).catch((err)=>{console.log("进入catch方法");});console.log('上面的代码抛出异常')async其他说明异步函数执行rejectpromise可能返回resolve或者reject。执行reject时,async函数需要定义catch方法functiongetData(){returnnewPromise((resolve,reject)=>{setTimeout(()=>{reject("fail");},1000);});}asyncfunctionfoo(){constpromise=awaitgetData();控制台日志(承诺);}foo()没有定义catch方法时,await执行结果会直接报错。await后面将跟一个表达式,该表达式将返回一个promise。await将等待promise解决后再继续执行await之后的表达式也有三种情况。该表达式与异步函数的返回值类型相同。expression是一个基本数据类型,会被Promise.resolve包裹起来,执行成功。表达式为promise,执行结果与promise一致。表达式实现了thenable对象,执行结果为then函数中的结果asyncfunctionfoo(){awaitPromise.reject("promise执行reject方法");console.log("willthefollowinglineofawaitexecute");}foo().catch((err)=>{console.log("err",err);});console.log("全局代码呢");当await后面的表达式执行失败时,下面的代码将不会执行。异步函数的执行顺序等待。下面的代码await需要等到await执行完后的表达式才执行asyncfunctionbar(){console.log("2");returnnewPromise((resolve)=>{resolve();});}asyncfunctionfoo(){console.log("1");等待酒吧();console.log("3");}foo();console.log("4");await后面的表达式实际上会执行promise的方法,所以await下面的代码实际上会放在microtask面试题中asyncfunctionasync1(){console.log('async1start')awaitasync2();安慰。log('async1end')}asyncfunctionasync2(){console.log('async2')}console.log('scriptstart')setTimeout(function(){console.log('setTimeout')},0)异步1();新的承诺(功能(解决){console.log('promise1')resolve();})。然后(函数(){console.log('promise2')})console.log('scriptend')定义了函数async1和async2,但没有调用,先输出"scriptstart"setTimeout中的内容会放在宏中task队列中最终执行了函数async1,输出“async1start”。函数async2被执行,输出“async2”。async2函数下面的输出“async1end”会被放入微任务队列中执行promise的executor部分,输出为“promise1”,then方法中的输出“promise2”会被放入微任务队列中输出“scriptend”执行microtask队列中的代码,然后输出“async1end”、“promise2”执行macrotask队列中的代码,输出“setTimeout”图标如下,执行结果为如下。以上就是async和await的推导过程和用法。关于高级js,开发者需要掌握的东西还是很多的。可以看看我写的其他博文,持续更新中~