写点什么

十分钟带你全面解析 Promise、generator、async 类同步编程!

  • 2022-11-18
    北京
  • 本文字数:2727 字

    阅读完需:约 9 分钟


javascript语言特性的影响,编程过程中充斥着大量异步回调,这会让代码维护起来特别麻烦,一步步走向回调地狱。社区中最早提出Promise解决方案,es6将其融入语法标准,并提供了generatorasync,向类同步编程不断努力。本文会通过这三个方面演示类同步进化过程。 ##1.Promise提供异步编程的容器,包含异步代码,在得到异步结果时,通过resolve传递数据(resove对应then所指定的函数,其实也就是单个过程的异步回调,可以理解成将之前的回调函数放在then方法中定义)。


以 ajax 请求封装为例:


  • 传统形式


function ajax(url, success) {       var xhr = new XMLHttpRequest();       xhr.open("GET", url);       xhr.send();       xhr.onreadystatechange = function () {           if (xhr.status == 200 && xhr.readyState == 4) {               //将请求结果作为实参传入成功回调               success(xhr.responseText);           }       }   }   //如果两个异步过程有先后顺序,则会出现这种嵌套情况   ajax("http://vebcoder.cn:9527/api/getTypeOne", function (res) {       console.log(res);       ajax("http://vebcoder.cn:9527/api/goodList", function (res) {           console.log(res);       })   })
复制代码


  • Promise 形式


function ajax(url) {     //promise容器包裹异步过程     return new Promise(resolve => {
var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.send(); xhr.onreadystatechange = function () { if (xhr.status == 200 && xhr.readyState == 4) { //将异步结果使用resolve进行传递 resolve(xhr.responseText); } }
})}

ajax("http://vebcoder.cn:9527/api/getTypeOne").then(res=>{ console.log(JSON.parse(res)) }).then(()=>{ return ajax("http://vebcoder.cn:9527/api/goodList")}).then(res=>{ console.log(JSON.parse(res))})
复制代码


解决了回调函数横向发展的问题,变成了纵向发展结构。直观确实很直观但是一大堆的then方法,!接下来generator登场



2.generator

乍一看,generator不过是一个有多个返回值的函数而已,奥妙在于如果不调用next方法,代码会停止执行的。


  • 基础用法


//function后加*function* Gen(){     console.log(1);     yield;     console.log(2)     yield;     console.log(3);     return;}//调用函数获得指针对象var g=Gen();g.next();//1g.next();//2g.next();//3
复制代码


第一次调用next执行到第一个yield,第三次执行到函数末尾return的位置。


  • 奥妙之处


function* Gen(){    //用变量接收yield命令    var res=yield;    console.log(res)}var g=Gen();g.next();//next传入参数g.next(100);//100
复制代码


第一次调用next方法,代码执行到yield停止执行。第二次调用next传入参数,代码继续执行,并将传入next的参数赋值给res变量。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。 那么我们就可以这样做:


//上述封装的ajax方法-传统形式function* Gen(){                                                 //请求成功开始下一步    ajax("http://vebcoder.cn:9527/api/getTypeOne",res=>{g.next(res)})    // 接收yield返回值    let res=yield;    console.log(res)//请求的数据结果}var g=Gen();// 开始执行代码g.next();
//上述封装的ajax方法-Promise形式function* Gen(){ //请求成功开始下一步 ajax("http://vebcoder.cn:9527/api/getTypeOne").then(res=>{g.next(res)}) // 接收yield返回值 let res=yield; console.log(res)//请求的数据结果}var g=Gen();// 开始执行代码g.next();
复制代码


使用口诀:上一步回调,下一步,接收yield等待结果传入




按理说这种形式已经不错了,不用再往下看了,除非你能忍住!



3.async

asyncgenerator的语法糖,你只需关注两部、步操作就行。相当于对Promisegenerator进行了融合。


async function Asy(){                                    //等待promise实例    let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne")    console.log(res)//请求的数据结果}Asy();
//结合自执行函数;(async function(){ let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne") console.log(res)//请求的数据结果}())
复制代码


async函数就是将Generator 函数的星号(*)替换成async,将yield替换成await。 注意:await 后面需要跟一个 promise 实例,无需手动传递结果!


最后来一个对比(有次序的异步过程):


//传统方式(对应上述传统ajax封装形式)ajax("http://vebcoder.cn:9527/api/getTypeOne", function (res) {    console.log(res);    ajax("http://vebcoder.cn:9527/api/goodList", function (res) {        console.log(res);    })})
//promise (对应上述promise ajax封装形式)ajax("http://vebcoder.cn:9527/api/getTypeOne") .then(res=>{ console.log(JSON.parse(res)) }) .then(()=>{ return ajax("http://vebcoder.cn:9527/api/goodList") }) .then(res=>{ console.log(JSON.parse(res)) })
//generator (对应上述promise ajax封装形式)function* Gen(){ //请求成功开始下一步 ajax("http://vebcoder.cn:9527/api/getTypeOne").then(res=>{g.next(res)}) // 接收yield返回值 let res=yield; console.log(res);
ajax("http://vebcoder.cn:9527/api/goodList").then(res=>{g.next(res)}) // 接收yield返回值 let res2=yield; console.log(res2);
}var g=Gen();// 开始执行代码g.next();
//async (对应上述promise ajax封装形式)// 发送请求;(async function(){ let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne") console.log(res)//请求的数据结果 let res2=await ajax("http://vebcoder.cn:9527/api/goodList") console.log(res2)//请求的数据结果}())
复制代码


async有更好的语义,几乎达到与同步代码一样的编程体验!




帮助到你的话就点个关注吧~


用户头像

还未添加个人签名 2022-10-21 加入

还未添加个人简介

评论

发布
暂无评论
十分钟带你全面解析Promise、generator、async类同步编程!_JavaScript_好程序员IT教育_InfoQ写作社区