网站建设知识

我们将想法与焦点与您一起共享

当前位置:深圳网站建设 > 网站建设知识> 深圳网站建设|用(yòng)Generators解决callback金字塔

深圳网站建设|用(yòng)Generators解决callback金字塔

2017-6-5 17:39:35 独占网络 网站建设知识
what is generator

Generators算得上js的一个新(xīn)概念函数。它看起来像是一个函数,但是可(kě)以暂停执行。从语法上看,有(yǒu)3点关注:

函数名(míng)前有(yǒu)一个*
函数内有(yǒu)yield
调用(yòng)时返回一个对象,对这个对象调用(yòng)next才会继续执行
你的node支持generator了吗?

在node 0.11以上,对node必须加入–harmony 参数,即可(kě)支持:

JavaScript

$ node --harmony
    > function *a(){}
    undefined
    >
 
看到undefined就说明支持了。如果不加参数,默认不支持。你会看到

JavaScript

$ node
    > function *a(){}
    ... 

声明一个generator 是这样的:

JavaScript

  function* ticketGenerator() {} 
如果想要 generator 提供一个值并暂停,那么需要使用(yòng)yeild 关键字。yield 就像 return 一样返回一个值。和它不同的是,yield会暂停函数。

JavaScript

function* ticketGenerator() {
      yield 1;
      yield 2;
      yield 3;
    } 
我们做了一个迭代器,叫做 ticketGenerator. 我们可(kě)以和它要一个值,然后它返回1,然后暂停。依次返回2,3:

JavaScript

    var takeANumber = ticketGenerator();
    takeANumber.next(); 
    // > { value: 1, done: false }
    takeANumber.next(); 
    // > { value: 2, done: false }
    takeANumber.next(); 
    // > { value: 3, done: false }
    takeANumber.next(); 
    // > { value: undefined, done: true } 
现在我们返回大為(wèi)3 ,不太有(yǒu)用(yòng).我们可(kě)以递增到无穷。无穷数列来了。

JavaScript

function* ticketGenerator() {
  for(var i=0; true; i++) {
    yield i;
  }
}
 
再来一遍:

JavaScript

var takeANumber = ticketGenerator();
console.log(takeANumber.next().value); //0
console.log(takeANumber.next().value); //1
console.log(takeANumber.next().value); //2
console.log(takeANumber.next().value); //3
console.log(takeANumber.next().value); //4 
每次叠加,无穷枚举。这就有(yǒu)点意思了。

干预yield返回值

除了可(kě)以枚举累加外, next() 还有(yǒu)第二种用(yòng)法:如果你传递一个值给next,它会作(zuò)為(wèi)yield 语句的返回值。我们可(kě)以利用(yòng)这个特性,把刚刚的无限数列做一次重置:

JavaScript

function* ticketGenerator() {
  for(var i=0; true; i++) {
    var reset = yield i;
    if(reset) { i = -1; }
  }

这样当我们调用(yòng)next(true)的时候,i会等于-1,从而重设了i值到初始值。

无需困惑, yield i 会把i发到generator的调用(yòng)next处,但是generator内部我们使用(yòng)next提供的值(如果提供了的话)。

看看效果:

JavaScript

var takeANumber = ticketGenerator();
console.log(takeANumber.next().value); //0
console.log(takeANumber.next().value); //1
console.log(takeANumber.next().value); //2
console.log(takeANumber.next(true).value); //0
console.log(takeANumber.next().value); //1 
这就是generator。古怪,有(yǒu)趣。接下来会继续分(fēn)析它的应用(yòng),在解决callback hell方面。

问题

拿(ná)一个案例开刀(dāo)吧。我们来看一个delay函数,延迟一些时间,然后打印点文(wén)字:

JavaScript

function delay(time, callback) {
  setTimeout(function () {
    callback("Slept for "+time);
  }, time);

调用(yòng)它也是常见代码:

JavaScript

delay(1000, function(msg) {
  console.log(msg);
  delay(1200, function (msg) {
      console.log(msg);
    }
})
//...waits 1000ms
// > "Slept for 1000"
//...waits another 1200ms
// > "Slept for 1200" 
為(wèi)了保证两次打印的次序,我们的办(bàn)法,就是通过callback来完成。

要是延迟多(duō)几次,比如12次,我们需要12次嵌套的callback,代码不段向右延伸。哇,回调金字塔。

呼叫Generators

异步是node的灵魂。可(kě)是异步的麻烦在于callback,因為(wèi)我饿每年需要等待完成通知,所以需要callback。

有(yǒu)了 generators,我们可(kě)以让代码等。无需callback。可(kě)以用(yòng)generators 在每个异步调用(yòng)进行中(zhōng),在调用(yòng)next()之前暂停执行。还记得yield/next 吗?这是generators的绝活。

怎么弄?

我们先得知道,我们要把异步调用(yòng)暂停需要用(yòng)到generator ,而不是典型的函数,所以加个星在函数前:

JavaScript

function* myDelayedMessages() {
    /* delay 1000 ms and print the result */
    /* delay 1200 ms and print the result */
}
 
加入delay调用(yòng)。delay需要callback。这个callback需要调用(yòng)generator.next(),以便继续代码。我们先放一个空的callback:

JavaScript

function* myDelayedMessages() {
    console.log(delay(1000, function(){}));
    console.log(delay(1200, function(){}));
}
 
现在代码依然是异步的。加入yield:

JavaScript

function* myDelayedMessages() {
    console.log(yield delay(1000, function(){}));
    console.log(yield delay(1200, function(){}));
}
 
又(yòu)近了一步。但是需要有(yǒu)人告诉generator向前走,走起来。

关键概念在这里:当delay完成时,需要在它的callback内执行点东西,这些东西让generator向前走(调用(yòng)next)

这个函数,且不管如何实现,我们知道它得叫做resume:

JavaScript

function* myDelayedMessages(resume) {
    console.log(yield delay(1000, resume));
    console.log(yield delay(1200, resume));

我们得把定义好的resume传递给 myDelayedMessages

变魔术了…

如何实现resume,它又(yòu)如何知道我们的generator?

给generator 函数加个外套,外套函数的功能(néng)就是启动generator,传递写好的resume,次拨动generator(调用(yòng)next),等待resume被调用(yòng),在resume内继续拨动generator。这样generator就可(kě)以滚动起来了:

JavaScript

function run(generatorFunction) {
    var generatorItr = generatorFunction(resume);
    function resume(callbackValue) {
        generatorItr.next(callbackValue);
    }
    generatorItr.next()

有(yǒu)点烧脑。当年写作(zuò)名(míng)噪一时的“goto statement considered harmful”的作(zuò)者,看到此代码非得气死。这里没有(yǒu)一行goto,却跳来跳去的比有(yǒu)goto的还难。

注意哦,我们利用(yòng)了next的第二个特性。resume 就是传递给callback 的函数,它因此接受了delay提供的值,resume传递这个值给 next, 故而 yield 语句返回了我们的异步函数的结果。异步函数的结果于是被console打印出来。就像“倒脱靴”。

代码整合起来:

JavaScript

run(function* myDelayedMessages(resume) {
    console.log(yield delay(1000, resume));
    console.log(yield delay(1200, resume));
})
//...waits 1000ms
// > "Slept for 1000"
//...waits 1200ms
// > "Slept for 1200" 
就是这样。我们调用(yòng)两次delay,按照次序执行,却没有(yǒu)callback的嵌套。如果要调用(yòng)12次,也还是没有(yǒu)callback嵌套。如果你依然迷惑不解,我们再次分(fēn)步来一遍》

run 以generator 為(wèi)参数,并且内部创建了一个resume 函数
run 创建一个generator函数,传递resume给它
然后run次调用(yòng)next,启动了generator函数到yield
generator 遇到了个yield,并调用(yòng)yield后的delay,然后暂停。
delay 在1000ms后完成,调用(yòng)resume
resume 告诉generator 在走一步。并且传递delay的结果给run函数,由console 打印
generator 遇到第二个yield, 调用(yòng)delay ,再次暂停
delay 在1200ms后完成,调用(yòng)resume
resume 告诉generator 在走一步。并且传递delay的结果给run函数,由console 打印
co 更好

上面谈到的做法,确实可(kě)以把异步改成同步了。可(kě)是并不太完美:比如resume显得比较突兀,在比如只能(néng)在callback返回一个值。不够通用(yòng)。

这样的话,可(kě)以考虑TJ开发的co。连resume的声明和引用(yòng)也省掉了。还是以delay為(wèi)例:

JavaScript

    var co = require('co');
    function delay(time) {
      return function (callback){
        setTimeout(function () {//
          callback(null,"Slept for "+time);
        }, time);
      }
    }

    co(function *() {
      console.log(yield delay(1000))
      console.log(yield delay(1200))  
    }) 
為(wèi)了和co适配,delay需要做些修改,去掉callback,返回一个带callback的函数,把计算结果通过callback传递出去。个参数依照node的规矩,留给err。

更绝。怪的不TJ被社區(qū)成為(wèi)大神。

再来一个。readFile(file,callback),作(zuò)為(wèi)常见的异步函数如何修改?

JavaScript

    var co = require('co');
    function readFile(file){
      return function (callback ){
        var fs = require("fs")
        fs.readFile(file,callback)
      }
    }

    co(function *() {
      console.log(yield readFile("./app.js"))
    })

    //<Buffer 76 61 72 20 63 ... > 
可(kě)是,readFile改造这样过工(gōng)作(zuò),纯粹就是boilerplate !所以,有(yǒu)人做了这样的工(gōng)作(zuò)。安(ān)装(zhuāng)co-fs,就可(kě)以:

JavaScript

    co(function *() {
      var fs = require("co-fs")
      var js = yield fs.readFile('./app1.js', 'utf8')
      var files = yield fs.readdir('.')
      console.log(js,files)
    })
 
node.js真是玩梯云纵。以為(wèi)已经很(hěn)好了,还是有(yǒu)人在加入一把火。

所以,值得去npm看看,查找下co-打头的库,有(yǒu)1000+个,要不要独立出去:):
 
打个总结

成功。我们用(yòng)generator替换了callback。我们这样做到的:

创建一个run函数,以 generator 為(wèi)参数, 并传递一个 resume 函数给它
传递resume 函数,单步推动generator ,返回任何异步callback获得的值给run
传递resume 作(zuò)為(wèi)异步调用(yòng)callback . 这些异步函数一旦完成,就调用(yòng)callback,因此就是调用(yòng)resume。允许resume推动generator

generators替代“callback hell” 是否佳是可(kě)争论的,但是这个练习可(kě)以帮助你理(lǐ)解到ES6的generators 和iterators

    深圳网站建设www.sz886.com

始终专注高端网站建设服務(wù) 网站建设案例服務(wù)方案联系

联系我们

135-3000-5572
151-1257-9390

地址:深圳市龙岗區(qū)横岗街(jiē)道联旺大厦5楼

邮箱:chenmh@sz886.com

我们的优势

12年建站服務(wù)经验自主开发后台CMS开发项目不外包无隐形收费

服務(wù)198家上市企业服務(wù)行业龙头超过70家 营销型网站建设完备的项目流程管理(lǐ)體(tǐ)系网页(yè)设计与网站开发技(jì )术并重

关于独占网络

十多(duō)年来,凭借对设计的深刻理(lǐ)解,对互联网营销趋势的敏锐洞察,独占网络不断修正服務(wù)导向,完善创作(zuò)品格,始终注重专业探索,為(wèi)所有(yǒu)合作(zuò)企业机构全力以赴,确保网站的视觉體(tǐ)验与营销转化能(néng)力。

我们是一群对互联网抱有(yǒu)执着信念的技(jì )术控。从2012年到现在,公(gōng)司从未建过强大的营销团队,却凭着作(zuò)品与服務(wù)不断保持增長(cháng),做到了"桃李不言,下自成蹊。" 我们坚信:每个客户都是一条渠道,每个案例都是一个广告,為(wèi)企业插上翅膀,助力企业转型升级,我们已做好准备。

专业团队為(wèi)您提供深圳网站建设、深圳网站制作(zuò)、深圳营销型网站建设、外贸网站建设等服務(wù),深圳建网站就找独占网络 | 12年专注网站建设

深圳市独占网络科(kē)技(jì )有(yǒu)限公(gōng)司 |备案号:京ICP证000000号| Copyright 2023,ALL Rights Reserved www.sz886.com | Copyright 2023版权所有(yǒu)
Hi,Are you ready? 如果您有(yǒu)意向
请于我们取得联系。

有(yǒu)一个互联网项目想和我们谈谈吗?
您可(kě)以填写右边的表格,让我们了解您的项目需求,这是一个良好的开始,我们将会尽快与你取得联系。当然也欢迎您给我们写信或是打電(diàn)话,让我们听到你的声音!

独占-整合互联网营销

地址:深圳市龙岗區(qū)横岗地铁D出口联旺大厦5楼
大客户专線(xiàn):深圳 13530005572
售前QQ:1447567909
E-mail: sales@sz886.cn

合作(zuò)意向表
您希望我们為(wèi)您提供什么服務(wù)?
国产吃瓜黑料一区二区 老师含着我的奶边摸边做无码视频 97人妻人人揉人人躁人人 飒爽妈咪1-100集免费 很黄的吸乳A片三男一女 今天高清视频在线观看 日本水蜜桃身体乳正品推荐 罚男仆夹震蛋器憋尿虐乳双性 成全视频大全高清全集 媚欢(出轨高H) 少女たちよ观看动漫第二季预告 国产伦精品一区二区三区妓女下载 今天免费高清在线观看 成全视频大全高清全集 欧美性猛交99久久久久99按摩 日本免费三色电费2024年 中国老熟女重囗味HDXX 两个男生做酿酿酱酱片易军 在教室伦流澡到高潮H强圩动漫 亚洲精品一区二区久 妖精漫画免费登录页面看漫画免费 成熟妇人A片免费看网站 丰满的女邻居做爰2 女儿的朋友63中汉字三义 巜大学生特殊精油按摩2 最好看的中文字幕国语电影 少女的免费高清中国 日剧大全免费观看电视剧在线 法国《熟妇的荡欲》 活色生香小说阅读全文 无敌高清在线观看免费 丰满熟女人妻一区二区三 你是我的女人6免费观看6集 《性妲己》电影在线观看 成全电影大全在线观看 国内老熟妇对白HDXXXX 《年轻的护士1》在线观看视频 娇妻被邻居灌满精H催眠 性少妇VIDEOSEXFREEXXXX片 一女多男3根一起进去 日本人裸体做爰视频 老女人做爰全过程免费的视频 色婷婷AV一区二区三区之红樱桃 你是我的女人6免费观看6集 韩漫漫画免费阅读看漫画下拉 国产熟妇与子伦HD 三个人一起躁我吃奶头80分钟 天天弄 嗯灬啊灬把腿张开灬A片视频网站 9I传媒有限公司 成全看免费观看完整版 啊灬啊灬啊灬快灬深草莓视频 喜欢男朋友一边C我一边骂我 一阴吞两阳与MACD的关系 无码一区二区三区 黑帮大佬和我的365日 性生生活12分钟免费 被伴郎的内捧猛烈进出H 花房姑娘8电视剧免费观看 成全在线观看免费完整版的方法 少妇无码 大肉大捧一进一出好爽动态图 一阴吞两阳与MACD的关系 漂亮人妻洗澡被强公BD 啊灬啊灬啊灬快灬高潮了听书 免费大片在线观看WWW 强辱丰满人妻HD中文字幕 他趴在我两腿中间吸我电影 CHINESE老太交GRANY 成全影视大全在线看 没带套子让校霸C了一节课 亚洲精品久久久久久一区二区 日本WINDOWSSERVER7777 敌伦交换小敏小静小雅第1集 三叶草欧码成人毛片 TXVLOGCOM糖心官网网站 胸一面膜上边一面膜下边免费 AA片在线观看视频在线播放 男人边吻奶边挵进去A片小说 一个好妈妈的D3申字电影