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

这次,我将在10分钟内帮你弄清楚async-await的原理!

时间:2023-03-27 17:53:46 JavaScript

Java博大精深,但如果只能同步运行,遇到HTTP网络请求、I/O处理、事件、定时器等耗时操作就会卡住。没用。那么js是怎么解决异步编程的呢?js中的回调函数往往将函数作为参数传递。当任务执行有结果时,调用该函数进行下一步。假设我们需要获取上一个请求的结果才能进行下一个请求。一旦请求多了,代码就会很难看。http.get("url",param,(err,res1)=>{console.log("res1:",res1)http.get("url",res1,(err,res2)=>{console.log("res2:",res2)http.get("url",res2,(err,res3)=>{console.log("res3:",res3)...})})})来自上面的代码可以看出,只嵌套了3次就已经有堆山的趋势了。..PromiseES6引入了Promise,一种新的js异步编程方案。Promise的链式调用至少让代码看起来统一了很多。一旦代码堆起来,还是影响阅读和维护。functionqueryData(url,param){returnnewPromise((resolve,reject)=>{http.get(url,param,(err,data)=>{resolve(data)})})}queryData("/api/user",data).then(res1=>queryData("/api/xx",res1)).then(res2=>queryData("/api/xx",res2)).then(res3=>queryData("/api/xx",res3)).then(finalRes=>console.log("finalRes:",finalRes)).catch(error=>console.log("error:",error))async/await最后我们在ES7中迎来了蓝天——async\await,使用它们,我们可以从上到下逐行编写我们的异步代码,进而达到视觉上同步的效果,读起来还是蛮舒服的。比如上面的代码可以改写如下asyncfunctionrequest(){constres1=awaitqueryData("/api/user",data)constres2=awaitqueryData("/api/user",res1)constres3=awaitqueryData("/api/user",res2)constfinalRes=awaitqueryData("/api/user",res3)console.log("finalRes:",finalRes)}瞬间提示这样写很爽:async/await必须一起使用,否则会报错。那么它的原理是什么呢?首先我们来了解协议进程的概念协程有点像线程,但它是一个更轻量级的存在,可以由我们自己编写程序来管理。它的步骤大致如下:协程A开始执行协程A执行到一半,进入暂停,一段时间后将执行权转移给协程B,协程B归还执行权,协程B进入暂停协程A恢复执行Genarator函数Genarator函数是协程的一个实现在js中,其声明方式如下:function*gen(){yield1yield2yield3}函数名前需要加星号,函数体中需要包含yield关键字。函数是一个生成器.调用后并没有执行函数体,而是返回一个迭代器对象。通过调用迭代器对象的next方法来执行生成器函数。第一个调用的执行会暂停,直到到达yield关键字,下一个调用会执行到下一个yield关键字,以此类推。调用iterator对象的next方法会返回一个对象{value:...,done:...},value是每次执行yield后的值,done是布尔值,false表示还有yield在函数还没有执行完之后,true表示执行完毕,没有yield。当done为真时,value是函数的返回值。也可以在调用iterator的next方法时传递参数,参数可以在yield后的赋值语句中赋值。如果不传参数,yield后的值会丢失。将async/await与genarator函数进行比较,你会发现async函数调用返回一个promise,而genarator函数调用返回一个迭代器对象。async函数不需要通过手动调用来执行函数体,也就是说它有自己的执行器并且使用async/await而不是*/yield具有更好的语义所以我们来炫耀一下,使用生成器函数并承诺实现我们的异步功能。asyncfunctionsomeFunction(args){//...}等同于:functionfn(num){returnnewPromise(resolve=>{setTimeout(()=>{resolve(num*2)},1000)})}function*gen(param){constres1=yieldfn(param)console.log("res1-->",res1)constres2=yieldfn(res1)console.log("res2-->",res2)constres3=yieldfn(res2)console.log("res3-->",res3)returnres3}functiongenToAsync(gen){returnfunction(){constg=gen.apply(this,arguments)returnnewPromise((resolve,reject)=>{functionrun(val){让结果尝试{result=g.next(val)}catch(err){returnreject(err)}const{value,done}=resultif(done){解决(价值)回报}returnPromise.resolve(value).then(res=>{run(res)}).catch(err=>{reject(err)})}run()})}}constasyncGen=genToAsync(gen)asyncGen(2).then(res=>console.log("res-->",res))执行结果从上面的代码我们可以看出已经实现了和async/await一样的效果