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,不过是追求喜新厌旧的年头!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335