异步流程控制库GoWithTheFlow

异步流程控制库GoWithTheFlow

一个尾触发方式来控制异步流程的库, 有seq(顺序执行) par(同步执行) 两种方法

博客
http://notes.jetienne.com/2011/07/17/gowiththeflow.js-async-flow-control-with-a-zen-touch.html

Github
https://github.com/lumixraku/gowiththeflow.js/blob/master/gowiththeflow.js

使用

顺序执行

  Flow().seq(function(next) {
    setTimeout(function(){
      console.log("first job");
      next('error', 'retValue');
    },500);
  }).seq(function(next, error, result) {
    console.log(error, result);
    console.log("second job. run *after* first job");
    next();
  });

同步执行
最后挂载的seq将会在所有par任务执行结束后执行
errors results是数组 保存所有的par的结果
执行结果顺序是挂载任务的顺序

   Flow().par(function(next){
        setTimeout(function(){
          console.log("job foo");
          next(null, "foo");
        },1000);
    }).par(function(next){
      setTimeout(function(){
        console.log("job bar");
        next(null, "bar");
      },500);
    }).par(function(next){
        setTimeout(function(){
        console.log("job zoo");
        next(null, "zoo");
        },500);
    }).seq(function(next, errors, results){
        console.log("job run *after* the completion of foo and bar");
        console.assert(errors.length == 3 && errors[0] === null && errors[1] == null)
        console.assert(results.length == 3 && results[0] === 'foo' && results[1] == 'bar')
        next();
    })

实现

var Flow = function() {
  var self, stack = [],
    //等待所有同步操作完成后开始执行异步的部分
    timerId = setTimeout(function() {
      timerId = null;
      self._next();
    }, 0);
  return self = {
    destroy: function() {
      timerId && clearTimeout(timerId);
    },

    //seq 和par 都只是挂载了函数(把函数保存在了stacks中)  并没有执行
    //同步执行的任务都在一个元素中
    //比如 stack = [  [f1()], [f2(), f3()], [f4()]   ]
    //表示 f1()   f2()f3()      f4()   三个顺序执行的任务   其中任务2  f2f3两个函数是并行执行
    par: function(callback, isSeq) {
      if (isSeq || !(stack[stack.length - 1] instanceof Array)) {
        stack.push([]);
      }
      stack[stack.length - 1].push(callback);
      return self; //链式调用
    },
    seq: function(callback) {
      return self.par(callback, true);
    },

    //调用一次_next  解决一次顺序任务
    _next: function(err, result) {
      var errors = [],
        results = [],
        callbacks = stack.shift() || [], //callbacks [function(next){....}]
        nbReturn = callbacks.length, 
        isSeq = nbReturn == 1; //表明是顺序任务  比如上面 [f1()] 这种情况
      for (var i = 0; i < callbacks.length; i++) {
        (function(fct, index) {
          //fct就是异步函数 fct接受三个参数 fct(next, err, result) 
          //而这个function(err, result) 就是next
          //next接受两个参数  next('error', 'retValue');
          fct(function(error, result) {
            errors[index] = error;
            results[index] = result;

            if (--nbReturn == 0) { //表明此次顺序任务执行完毕  比如上面[f2,f3] 到f3的时候
              self._next(isSeq ? errors[0] : errors, isSeq ? results[0] : results)
            }
          }, err, result);
        })(callbacks[i], i);
      }
    }
  }
};

// export in common js
if (typeof module !== "undefined" && ('exports' in module)) {
  module.exports = Flow;
}

// Asynchronous Module Definition - http://requirejs.org/docs/whyamd.html
if (typeof define === 'function' && define.amd) {
  define('Flow', [], function() {
    return Flow;
  });
}

posted @ 2015-11-27 20:36  cart55free99  阅读(181)  评论(0编辑  收藏  举报