co & thunkify

co

以前在generator中已經介紹過Co了javascript

戳這裏
http://www.cnblogs.com/cart55free99/p/4893498.htmlhtml

co通常和thunkify一塊兒使用 可以使得generator用起來更方便 因此co就是一個generator的流程控制模塊
以fs.readFile做爲例子java

先把readFile thunkify一下
app

fs.readFile(filename, callback)

變成異步

readThunk(filename)(callback)

這樣的調用形式async

co的用法

co(function* (){
    var fs1 = yield readThunk('a.txt', 'utf8');
    var fs2 = yield readThunk('b.txt', 'utf8');
    //...
})

你能夠像Async那樣用同步的方式書寫異步代碼
這裏的fs1 fs2就是 a.txt b.txt文件中的內容
真奇怪 fs1 fs2 的值應該是由 gen.next() 傳入啊,
難道說 gen.next() 傳入了 readThunk獲得的文件內容?
沒錯 就是這樣函數

下面簡單說說co的源碼this

function co(gen) {
  var ctx = this;
  var args = slice.call(arguments, 1)
  return new Promise(function(resolve, reject) {
    gen = gen.apply(ctx, args);

    //onFulfilled實際上調用第一個gen.next();
    onFulfilled();


    //爲了可以這樣調用 var a = yield asyncFuntion();
    //那麼就須要將前一個async的返回值經過 gen.next()傳給 變量a
    //也就是將res這個值給a
    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      next(ret);
    }


    function onRejected(err) { ... }

    function next(ret) {
      if (ret.done) return resolve(ret.value);
      //將異步函數轉爲一個Promise對象 value是一個Promise對象
      var value = toPromise.call(ctx, ret.value);
      //判斷是不是一個Promise對象 就是看是否有then()
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
      
    }
  });
}

可見用一個Promise 來處理異步函數 將異步函數readFile的結果經過Filfilled這個callback再次調用gen.next() 因此fs1 fs2 就是文件內容
不過即便thunkify以後 至始至終貌似都只向 readThunk傳了一個參數 callback呢?code

仔細研究就會發現通常的回調函數都是 function(err, data)的形式 因此co在
thunkToPromise 中用一個通用的回調函數 不用本身寫回調函數了
這個回調函數就是將 data resolve 並返回一個Promisehtm

fn就是異步函數

return new Promise(function (resolve, reject) {
    fn.call(ctx, function (err, res) {
      if (err) return reject(err);
      if (arguments.length > 2) res = slice.call(arguments, 1);
      resolve(res);
    });
  });

Promise success的那部分調用 Fulfilled 也就是再次調用了gen.next

co基本的處理流程就是這樣

相關文章
相關標籤/搜索