co源碼解讀

最近在學習使用Koa.在看官網的例子的時候時候看到它的中間件的級聯模式是經過生成器實現的,以後瞭解到Koa的級聯是經過Co這個庫實現的,下面就是對這個庫的代碼的主要流程的部分解讀git

1.生成器基礎es6

2.代碼解讀github

1.生成器基礎編程

這個是infoq的深刻淺出ES6中生成器的一章   生成器基礎api

 

能夠經過下面的代碼片斷去大體的理解Co函數的執行過程  生成器能夠經過next來實現任務的串行執行  next方法返回一個對象 有value屬性(yield執行的值) done 是否還有未執行的yield邏輯 同時還能將參數經過next進行傳遞 供下面的邏輯調用數組

 

function *test() {
    var x = yield 1;
    yield console.log(x);
}

var a = test();
var temp = a.next();
a.next(temp.value)  //1
View Code

 

2. 代碼解讀部分promise

function objectToPromise(obj){
  var results = new obj.constructor();
  var keys = Object.keys(obj);  //Object.keys()返回一個對象全部可枚舉屬性的數組
  var promises = [];//保存對象中promise運行的結果
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];//
    var promise = toPromise.call(this, obj[key]);
    if (promise && isPromise(promise)) defer(promise, key);//將原對象屬性中Promise的與數組關聯
    else results[key] = obj[key];
  }
  return Promise.all(promises).then(function () {
    return results;
  });//Promise接受一個Promise對象的數組做爲參數 當數組裏面所有變成resolve或者reject狀態

  function defer(promise, key) {
    // predefine the key in the result
    results[key] = undefined;
    promises.push(promise.then(function (res) {
      results[key] = res;   //romise的then方法不單單是註冊resolve的回調 還會將回調函數的返回值進行變換 返回promsie
      對象
    }));
  }
}
View Code

 Co將中間的結果和函數都進行了Promise的封裝  主要看下這個objectToPromise(obj)  功能就是將一個對象轉換爲Promise對象 這裏須要理解這兩個方法 Promise.all  它接受一個Promsie數組 當數組中所有爲resolve時,它就變成resolve,當其中有一個出現reject的時候,就進入reject狀態。能夠經過下面的代碼簡單的理解它的使用app

var promise1 = new Promise(function(resolve,reject){
    resolve(1);
});
var promise2 = new Promise(function(resolve,reject){
    resolve(2);
});
Promise.all([promise1,promise2]).then(function(){
    console.log('ok');
});
View Code

接下來講說這個defer(promise,key) 它的功能就是將原來對象的值裝換爲promise以後,經過數組的方式傳遞給外部異步

  function defer(promise, key) {
    // predefine the key in the result
    results[key] = undefined;
    promises.push(promise.then(function (res) {
      results[key] = res;   promise的then方法不單單是註冊resolve的回調 還會將回調函數的返回值進行變換 返回promsie
      對象
    }));
  }
View Code

promise.then  這個方法是返回一個Promise對象 這樣經過then方法將全部鍵值的執行結果都轉換爲Promsie對象 在經過數組的方式傳遞給外部 當全部鍵值執行都爲resolve的時候 就將總體的結果返回給外部 也就完成了對obj對象的封裝。async

下面就來理解下Co函數

function co(gen) {
  var ctx = this;
  var args = slice.call(arguments, 1);

  // we wrap everything in a promise to avoid promise chaining,
  // which leads to memory leak errors.
  // see https://github.com/tj/co/issues/180
  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.apply(ctx, args);
    if (!gen || typeof gen.next !== 'function') return resolve(gen);

    onFulfilled();

    /**
     * @param {Mixed} res
     * @return {Promise}
     * @api private
     */

    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      next(ret);
      return null;
    }

    /**
     * @param {Error} err
     * @return {Promise}
     * @api private
     */

    function onRejected(err) {
      var ret;
      try {
        ret = gen.throw(err);
      } catch (e) {
        return reject(e);
      }
      next(ret);
    }

    /**
     * Get the next value in the generator,
     * return a promise.
     *
     * @param {Object} ret
     * @return {Promise}
     * @api private
     */
     //co函數的核心就是這個next理解 經過next傳遞將上一個generator執行的結果往下傳遞而且進行了Promise的封裝
    function next(ret) {
      if (ret.done) return resolve(ret.value);
      var value = toPromise.call(ctx, ret.value);
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
      return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
        + 'but the following object was passed: "' + String(ret.value) + '"'));
    }
  });
}
View Code
 

參考  Generator與異步編程   Co

相關文章
相關標籤/搜索