over 2 years ago

為了要了解 Javascript ES6 Generator Function ,花了些許時間看了 co 的原始碼。

co 是一個 library 用來協助使用者輕鬆的利用 generator 來控制你的程式 flow 。co 會主動的幫你把一個 generator 函數內的所有的 yield 語句都跑過一遍,袪除了要一直用 next 控制 flow 的麻煩。yield 後面僅接受 generator, promise, function, array ,是使用上的一個限制。

以下節錄了 co 的原始碼:

function co(gen) {
  .
  .
  .
  return new Promise(function(resolve, reject) {
    onFulfilled();

    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      next(ret);
    }
    .
    .
    .
    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) + '"'));
    }
  });
}

流程

co 首先接受一個 generator function 並返回一個 promise。這個 promise 執行的第一個函數是 onFulfilled,從這個進入函數,開始了 generator 的第一個 next 。

自動走完所有整個 generator 的關鍵在於

var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);

yield 獲取到的 function, generator 轉為 promise ,並將 onFulfilled, onRejected 設定為它的 callback 函數,如此一來,一旦此函數執行完畢,會繼續執行原有的 generator ,不斷的重複前面的步驟,直到整個 flow 都走過一遍,當函數執行完畢也就是 ret.done === true ,這時就會呼叫 resolve 結束這個這個 promise 並呼叫對應的 callback 函數。當然,若是中途有任何錯誤發生就會呼叫 reject

← Context in React.js
 
comments powered by Disqus