资讯专栏INFORMATION COLUMN

co-parallel & co-gather源码解析

caozhijian / 1489人阅读

摘要:昨天也是好好的看了一下的源码,今天打算自己来做一下解析。源码如下这段代码真的是很短,但是方法真的很巧妙。因为两个方法用到了,这里把的源码也贴出来源码的描述就是为了执行而创建的。最后再次感谢提供的思路。

原文链接,转载请注明出处

最近看了Ma63d关于爬虫的这篇文章,正好自己也在做爬虫,看到他在文中提到了co-parallel和co-gather,就打算改一下自己的代码(本来代码就只是为了爬一些自己感兴趣的东西,现在还在改,地址在这里)。昨天也是好好的看了一下co-parallel的源码,今天打算自己来做一下解析。

co-parallel

源码如下:

var thread = require("co-thread");

module.exports = function *parallel(thunks, n){
  var n = Math.min(n || 5, thunks.length);
  var ret = [];
  var index = 0;

  function *next() {
    var i = index++;
    ret[i] = yield thunks[i];
    if (index < thunks.length) yield next;
  }

  yield thread(next, n);

  return ret;
};

这段代码真的是很短,但是方法真的很巧妙。因为两个方法用到了co-thread,这里把co-thread的源码也贴出来:

function thread(fn, n) {
  var gens = [];
  while (n--) gens.push(fn);
  return gens;
}

Run fn n times in parallel.

源码的描述就是为了parallel执行而创建的。由于在next外部创建了一个index变量,通过控制index的变化就可以使得每次执行的next函数都是不同的函数,在next中继续递归yield自己的话就是可以继续执行不同的next,最终把所有的thunks都yield了一遍,方法是不是很巧妙。

如果你觉得我说的话很混乱,那我们还是还是拿一个co-parallel中的例子来讲吧

var request = require("co-request");
var co = require("co");
var parallel = require("co-parallel");

var urls = [
  "http://google.com",
  "http://yahoo.com",
  "http://ign.com",
  "http://cloudup.com",
  "http://myspace.com",
  "http://facebook.com",
  "http://cuteoverload.com",
  "http://uglyoverload.com",
  "http://segment.io"
];

function *status(url) {
  console.log("GET %s", url);
  var s = (yield request(url)).statusCode;
  return s;
}

co(function *(){
  var start = Date.now();
  var reqs = urls.map(status);
  var res = yield parallel(reqs, 3);
  console.log(res);
  console.log("duration: %dms", Date.now() - start);
});

直接看到var reqs = urls.map(status);这句,由于传递给map的callback是一个Generator函数,所以最后的返回就是Generator的内部指针,也就是Iterator,也就是status()执行了一遍返回的结果。

再到var res = yield parallel(reqs, 3);这里,由于parallel是一个Generator,所以直接进入parallel中,因为n=3所以thread返回的数组内容应该是类似这个 [function*() {yield thunks[0]},function*(){yield thunks[1]}]。由于yield thread返回的结果是数组,在co中会对数组做Promise.all(obj.map(toPromise, this));因为obj中都是Generator,所以toPromise会直接对每一个Generator继续调用co(function*(){yield thunk[i]})。在next中最后又继续yield自己,所以当当一个thunk结束之后会继续下一个thunk。

co-gather

co-gather实现的和co-parallel差不多的功能,只是增加了并行错误处理机制。因为Promise.all方法会在其中任何一个出问题的时候都把错误扔出来, co-gather是对all中每一个方法都做了错误处理,让Promise.all方法不会抛错,源码如下:

var thread = require("co-thread");
module.exports = function *gather(thunks, n){
  n = Math.min(n || 5, thunks.length);
  var ret = [];
  var index = 0;
  function *next() {
    var i = index++;
    ret[i] = {isError: false};
    try {
      ret[i].value = yield thunks[i];
    } catch (err) {
      ret[i].error = err;
      ret[i].isError = true;
    }
    if (index < thunks.length) yield next;
  }
  yield thread(next, n);
  return ret;
};

和co-parallel不同的地方就在于对yield thunks[i]做了一层try catch,然后返回的包含执行结果的对象。

总结

单单是看parallel的代码还是很好理解的,但是由于自己co的源码理解的不好,所以自己在捋清example的时候有点混乱了,后来又重新仔细的看了一遍了co的源码以及阮一峰的Generator的讲解,自己才弄明白。最后再次感谢Ma63d提供的思路。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86707.html

相关文章

  • vueparseHTML函数拿到返回值后的处理源码解析

      承继上篇内容:下面是parseHTML 函数源码解析  varstartTagMatch=parseStartTag();   if(startTagMatch){   handleStartTag(startTagMatch);   if(shouldIgnoreFirstNewline(startTagMatch.tagName,html)){   advance(1);   }   co...

    3403771864 评论0 收藏0
  • 解析ahooks整体架构及React工具库源码

     这是讲 ahooks 源码的第一篇文章,简要就是以下几点:  加深对 React hooks 的理解。  学习如何抽象自定义 hooks。构建属于自己的 React hooks 工具库。  培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。  注:本系列对 ahooks 的源码解析是基于v3.3.13。自己 folk 了一份源码,主要是对源码做了一些解读,可见详情。  第一篇主要介绍 a...

    3403771864 评论0 收藏0
  • vue parseHTML函数源码解析AST基本形成

      vue parseHTML函数解析器遇到结束标签,在之前文章中已讲述完毕。  例如有html(template)字符串:  <divid="app">   <p>{{message}}</p>   </div>  产出如下:  {   attrs:["id="app"","id...

    3403771864 评论0 收藏0
  • Vue编译器解析compile源码解析

      现在我们讲compileToFunctions 的使用方法,现在看看内容:  //compile   varcompiled=compile(template,options);  其实真正应该讲的就是 compile 函数。  解析 compile  上述代码在调用 compile ,其中模板字符串 template ,就是让选项参数 options 的第二个参数传递给 compile 函数...

    3403771864 评论0 收藏0
  • Vue源码解析(三)-computed计算属性&amp;&amp;lazy watcher

    摘要:前言源码解析一模版渲染源码解析二双向绑定官网给出的如下结果源码分析判断参数是否包含属性本例中本例中和是函数监听计算属性设置,延迟执行的方法设置可以通过本例方式访问计算属性对象初始化时会针对属性的所有值分别一个对象,在源码解析二中有详细介 前言 1、Vue源码解析(一)-模版渲染2、Vue源码解析(二)-MVVM双向绑定 demo 官网给出的demo如下 new Vue({ el...

    CoderStudy 评论0 收藏0

发表评论

0条评论

caozhijian

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<