Promise、generator、async类同步编程

javascript语言特性的影响,编程过程中充斥着大量异步回调,这会让代码维护起来特别麻烦,一步步走向回调地狱。社区中最早提出Promise解决方案,es6将其融入语法标准,并提供了generatorasync,向类同步编程不断努力。本文会通过这三个方面演示类同步进化过程。

1.Promise

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();//1
g.next();//2
g.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有更好的语义,几乎达到与同步代码一样的编程体验!

2019,不过是追求喜新厌旧的年头!

版权声明:
作者:ht
链接:https://www.techfm.club/p/45503.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>