异步javascript,callback、Promise?我们用Generator!

ES6提供了两个处理异步Js的特性:Promise和Generator。我们这里会介绍这两个新特性,并在最后讲解如何使用Generator。为了使本文更加贴近实际,我们使用一个网络请求库request来作为异步任务的实例使用。

request库是一个强大而简单易用的网络请求库。她支持http和https,也支持redirect。以后在新的工作里也许就会用得着。

基本概念

如果你使用过其他的编程语言,那么一般调用方法的时候是这样的:

let result = function(...);
console.log(`${result}`);

他们都是顺序执行,方法执行完成之后打印结果。

但是在nodejs里,对于异步执行的js是行不通的,比如异步下载一个文件、HTTP访问一个接口等。除非获取result的方法调用可以等待,一直到结果返回之后再调用console.log(${result});

在ES6之前,代码是没办法停下来的。所以我们只有使用回调:

var request = require('request');

request('http://www.baidu.com', (err, res, body) => {
    if (err) {
        console.log(`ERROR:- ${err}`);
        return;
    }

    console.log(`Request done`);
});

request执行完成的时候就会调用(err, res, body) => {}的回调。

Promise是一个更好的处理回调的方法。更多内容可以看这里

// 1
var Promise = require('bluebird');
var request = require('request');

// 2
Promise.promisifyAll(request);

// 3
request.getAsync('http://www.baidu.com').then((data)=>{
    console.log('request');
    console.log(`${data.body}`);
});
  1. 引入bluebird库。bluebird就是一个在ES5下实现Promise的库。
  2. 使用bluebird库把request库全部的方法都转化为返回Promise对象的方法。在调用这些方法的时候只需要在原方法名称后加Async的后缀。
  3. 调用Promise化的方法。这时你可以调用then方法了。

ES6中可以使用Generator了。不严谨的说Generator主要由两部分组成。一个是function关键字后面的*****号,一个是方法体中的yield语句。如:

function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

最后结果是多少?

使用第三方库可以使得Generator方法暂停、在运行。基本上是这样的:

var Promise = require('bluebird');
var request = require('request');

Promise.promisifyAll(request);

var testFunc = Promise.coroutine(function *() {
    console.log('hello world');
    // let result = yield Promise.resolve('hello yield world');
    let result = yield request.getAsync('http://www.baidu.com');
    console.log(`${result}`);
    return result;
});

testFunc().then(value => {
    console.log(`### ${value}`);
});

注意:yield后面的语句必须是一个Promise,最后return的也是一个Promise。

request.getAsync('http://www.baidu.com');
    console.log(`${result}`);
    return result;
});

在上文已经介绍过,这个是被bluebird库Promise化之后的方法调用,返回的就是一个Promise。

代码

这里深入探讨一下Generator。那么,就请主角入场:

function *echo(text, delay = 0) {
    const caller = yield;
    setTimeout(() => caller.success(text), delay);
};

这是一个Generator方法,在执行的时候会在const caller = yield;这一句暂停,等待获取caller对象。在下面的例子里echo方法会被顺序的执行三次:

run(function* () {
    console.log(yield echo('this'));
    console.log(yield echo('is'));
    console.log(yield echo('a test'));
});

//Output:
//this
//is
//a test

上面的代码的并行执行例子:

run(function* parallelEchos() {
    let startTime = Date.now();
    let texts = yield [
        echo('this', 1000),
        echo('is', 900),
        echo('a test', 800)
    ];
    console.log(`##Parallex:- ${texts}`);
    console.log(`##Time used:- ${Date.now() - startTime}`);
});

//Output:
//##Parallex:- this,is,a test
//##Time used:- 1005

如果在一个Generator方法里yield一个Generator方法数组的话,数组里的这些方法会并行执行。最后耗时远小于顺序执行的时间。

最后

ES7的proposal里有一个async-await关键字的组合。解决了一个Generator非常的大的问题。Generator需要调用next方法来不断的往下执行yield语句,要自动执行就需要一个执行器,比如TJ的cobluebirdcoroutine方法实现了这个功能。

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

推荐阅读更多精彩内容