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

javascript异步编程的generator(生成器函数)和asnyc-await语法糖

时间:2023-03-27 18:09:42 JavaScript

Generator异步解决方案Promise相对于传统的处理异步调用的回调函数,最大的优势在于可以链式解决回调问题嵌套。但是,仍然会有大量的回调函数这样写。虽然它们之间没有嵌套,但仍然没有达到传统同步代码的可读性。如果按照下面的方式编写异步代码,非常简洁易读。//像同步模式{constvalue1=ajax('/api/url1')console.log(value1)constvalue2=ajax('/api/url1')console.log(value2)constvalue3=ajax('/api/url1')console.log(value3)constvalue4=ajax('/api/url1')console.log(value4)constvalue5=ajax('/api/url1')console.log(value5)}catch(err){console.log(err)}ES2015提供了一个生成器函数(GeneratorFunction)。它与普通函数的语法区别在于,在函数语句之后,函数名之前,有一个“*”作为生成器函数的标识。当我们调用生成器函数的时候,他不会立即执行这个函数,而是会得到一个生成器对象。直到我们手动调用对象的next方法,函数体才会开始。我们可以使用关键字yield来向外部返回一个值,我们可以在next方法的返回值中获取这个值。另外,返回的属性中有一个done关键字,表示生成器是否已经执行完毕。yield不会像return那样结束函数的执行,只是暂停函数的执行,直到下一次加载项调用next方法。executefunction*foo(){console.log('start')yield'foo'}constgenerator=foo()constresult=generator.next()调用next方法时,如果传入了参数,那么传入的参数in会作为yield关键字函数的返回值*foo(){console.log('start')//我这里可以接收到next传入的参数constres=yield'foo'console.log(res)//这是我传入的参数}constgenerator=foo()constresult=generator.next('这是我传入的参数')console.log(result)//{value:'foo',done:false}如果我们调用生成器函数的throw方法,这个方法会在生成器函数内部抛出异常function*foo(){console.log('start')//我可以在这里接收下一个输入参数constres=yield'foo'console.log(res)//这是我传入的参数}catch(err){console.log(err.message)//抛出错误}}constgenerator=foo()constresult=generator.next('这是p我传入的参数')console.log(result)generator.throw(newError('throwinganerror'))使用生成器函数和Promise实现异步编程体验函数ajax(url){returnnewPromise((resove,reject)=>{varxhr=newXMLHttpRequest()xhr.open('GET',url)//新方法可以直接接受一个j对象xhr.responseType='json'xhr.onload=function(){if(this.status===200){resolve(this.response)}else{reject(newError(this.statusText))}}xhr.send()})}function*main(){constuser1=yieldajax('/json1.json')console.log(user1)constuser2=yieldajax('/json2.json')console.log(user2)constuser3=yieldajax('/json3.json')console.log(user3)}constg=main()constresult=g.next()result.value.then(data=>{constresult2=g.next(data)if(result2.done)returnresult2.value.then(data2=>{constresult3=g.next(data2)if(result3.done)returnresult3.value.then(data3=>{g.next(data3)})})})显然生成器的执行者可以调用constg=main()functionhandleResult(result){if(result.done)returnresult.value.then(data=>{handleResult(g.next(data))},err=>{g.throw(err)})}handleResult(g.next())的生成器函数的调用其实它们都是相似的,所以我们可以写一个更通用的执行函数{handleResult(g.next(data))},err=>{g.throw(err)})}handleResult(g.next())}co(main)当然这样的executor社区已经有一个了比较完整的库库。这个co方案在2015年之前很流行,后来async/await语法糖发布后,这个方案就相对没那么流行了。使用生成器方法最明显的变化是异步调用返回到平面异步/等待。有了generator,js异步编程基本上和同步代码有类似的体验,但是使用generator这样的异步方案还是需要手动完成。写一个executor函数会比较麻烦。在ES2017版本中,新增了一个名为async的函数,同样提供了这种扁平化的编程体验,是语言层面的标准异步编程语法。其实async函数是生成器函数的一个更方便的语法糖,所以生成器函数的语法是类似的。asyncfunctionmain(){try{constuser1=awaitajax('/json1.json')console.log(user1)constuser2=awaitajax('/json2.json')console.log(user2)constuser3=awaitajax('/json3.json')console.log(user3)}catch(error){console.log(error)}}main()async函数返回一个Promise对象,更有利于控制整体代码promise.then(()=>{console.log('allcompleted')}).catch(err=>{console.log(err)})原文地址:https://kspf.xyz/archives/21更多内容微信公众号搜索小程序,用白米饭充饥