Javascript异步解决方案的发展历程

1.回调函数

function f1(callback){
    setTimeout(function(){
        //f1的任务代码
        callback();
    },1000);
}
f1(f2);
ajax('XXX1', () => {
    // callback 函数体
    ajax('XXX2', () => {
        // callback 函数体
        ajax('XXX3', () => {
            // callback 函数体
        })
    })
})

优点:便于理解
缺点:回调地狱,不能捕获错误

2.事件监听

f1.on('done', f2);
function f1(){
    setTimeout(function () {
      // f1的任务代码
      f1.trigger('done');
    }, 1000);
  }

容易理解,可以绑定多个事件,每个事件可以指定多个回调函数;缺点,整个流程都要变成事件驱动型,运行流程会变得不清晰。

3.发布/订阅(观察者模式)

jQuery.subscribe("done", f2);
function f1(){
    setTimeout(function () {
      // f1的任务代码
      jQuery.publish("done");
    }, 1000);
}
jQuery.unsubscribe("done", f2);

与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

4.Promises对象

Promise就是为了解决callback的问题而产生的
Promise实现了链式调用,也就是说每次then后返回的都是一个全新的Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装

ajax('XXX1')
  .then(res => {
      // 操作逻辑
      return ajax('XXX2')
  }).then(res => {
      // 操作逻辑
      return ajax('XXX3')
  }).then(res => {
      // 操作逻辑
  })

解决了回调地狱的问题,无法取消 Promise ,错误需要通过回调函数来捕获

5.Generator

特点:可以控制函数的执行,Generator函数是协程在ES6中的实现,最大的特点就是可以交出函数的执行权(即暂停执行)
执行Generator函数后会返回一个遍历器对象(Iterator)。本质上Generator是一个状态机,每次的遍历Generator函数返回的都是函数内部的每个状态。

    function* gen() {    
        yield 1;    
        yield 2;    
        return 1;
      }
      var g = gen();
      gen.next() // {value:1,done:false}
      gen.next() // {value:2,done:false}
      gen.next() // {value:3,done:true}

Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。缺点还需要编写自动执行器

6.使用async函数

async函数的实现就是将Generator函数和自动执行器包装在一个函数中

function async gen(){
    awiat 1;
    awiat 2;
}

异步编程的语法目标,就是怎样让它更像同步编程,使用async/await的方法,使得异步编程与同步编程看起来相差无几了。

7.借助流程控制库

NPM社区中出现了很多流程控制库可以供开发者直接使用,其中很流行的就是async库,该库提供了一些流程控制方法,其官方文档见http://caolan.github.io/async/docs.html
如果需要执行的任务紧密结合。下一个任务需要上一个任务的结果做输入,应该使用瀑布式
如果多个任务必须依次执行,而且之间没有数据交换,应该使用串行执行
如果多个任务之间没有任何依赖,而且执行顺序没有要求,应该使用并行执行

8.使用Web Workers

Web Worker是HTML5新标准中新添加的一个功能,Web Worker的基本原理就是在当前javascript的主线程中,使用Worker类加载一个javascript文件来开辟一个新的线程,起到互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口:postMessage,onmessage。其数据交互过程也类似于事件发布/监听模式,异能实现异步操作

9 对比

异步读取文件

1.回调函数

fs.readFile(fileA,(err,data)=>{
    if(err) throw err;
    console.log(data);
    fs.readFile(fileB,(_err,_data)=>{
        if(_err) throw err;
        console.log(_data)
    })
}

2.使用Promise

var fs = require('fs');
var readFile = function(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if (err) reject(err)
            resolve(data)
        })
    })
}
readFile(fileA)
.then((data)=>{console.log(data)})
.then(()=>{return readFile(fileB)})
.then((data)=>{console.log(data)})
// ... 读取n次
.catch((err)=>{console.log(err)})

3.使用Generator

var fs = require('fs');

var readFile = (path) => {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if (err) reject(err)
            resolve(data)
        })
    })
}

var gen = function* () {
    var f1 = yield readFile(fileA);
    var f2 = yield readFile(fileB);
    console.log(f1.toString());
    console.log(f2.toString());
}
gen.next()
grn.next()

4.使用Async

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

推荐阅读更多精彩内容

  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 2,654评论 0 5
  • 前言 编程语言很多的新概念都是为了更好的解决老问题而提出来的。这篇博客就是一步步分析异步编程解决方案的问题以及后续...
    李向_c52d阅读 1,029评论 0 2
  • 一、Javascript实现异步编程的过程以及原理 1、为什么要用Javascript异步编程 众所周知,Java...
    Ebony_7c03阅读 828评论 0 2
  • JavaScript语言的执行环境是‘单线程’的(也就是说,执行后续的代码之前必须完成前面的任务,也就是采用的是阻...
    kim_jin阅读 555评论 0 0
  • 我从小就热爱画画,但作品不多,没有参加过专业训练班,一直很遗憾。也喜欢设计,却没做成设计师。有很多人跟我一样,被迫...
    桥焰阅读 714评论 12 12