成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

co源碼解讀

xavier / 2924人閱讀

摘要:提取函數(shù)方便使用暴露把函數(shù)包起來(lái),返回執(zhí)行不帶參數(shù)的函數(shù),返回如果是函數(shù),直接執(zhí)行,指定作域判斷等價(jià)于,判斷函數(shù)是否執(zhí)行完根據(jù)返回值是否,執(zhí)行完就通過(guò)返回,外部將會(huì)執(zhí)行函數(shù)帶參數(shù)用于修改上一次結(jié)果,引擎會(huì)忽略第一次執(zhí)行時(shí)參數(shù)用于捕獲錯(cuò)誤執(zhí)行

/**
 * 提取slice()函數(shù)方便使用
 */

var slice = Array.prototype.slice;

/**
 * 暴露 `co`.
 */

module.exports = co["default"] = co.co = co;

/**
 * 把generator函數(shù) `fn` 包起來(lái),返回promise
 * This is a separate function so that
 * every `co()` call doesn"t create a new,
 * unnecessary closure.
 *
 * @param {GeneratorFunction} fn
 * @return {Function}
 * @api public
 */

co.wrap = function (fn) {
  createPromise.__generatorFunction__ = fn;
  return createPromise;
  function createPromise() {
    return co.call(this, fn.apply(this, arguments));
  }
};

/**
 * 執(zhí)行不帶參數(shù)的generator函數(shù),返回promise
 *
 * @param {Function} fn
 * @return {Promise}
 * @api public
 */

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) {
    //如果是函數(shù),直接執(zhí)行,apply指定作域
    if (typeof gen === "function") gen = gen.apply(ctx, args);
    // 判斷等價(jià)于 !(gen && typeof gen.next === "function"),判斷generator函數(shù)是否執(zhí)行完(根據(jù)返回值是否Iterator Object),執(zhí)行完就通過(guò)resolve返回,外部將會(huì)執(zhí)行`.then`函數(shù)
    if (!gen || typeof gen.next !== "function") return resolve(gen);

    onFulfilled();

    /**
     * .next帶參數(shù)用于修改上一次yield結(jié)果,V8引擎會(huì)忽略第一次執(zhí)行時(shí)參數(shù)
     * try/catch 用于捕獲錯(cuò)誤
     * 執(zhí)行完的結(jié)果交給自定義的next函數(shù),res結(jié)構(gòu)應(yīng)該是 {value, done}
     */

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

    /**
     * 自己捕獲err
     * 注意,這里是調(diào)用generator遍歷器上的throw方法
     * 一個(gè)generator執(zhí)行出錯(cuò)后就不再執(zhí)行,返回{value:undefined, done: true},故這里調(diào)用next函數(shù)會(huì)在第一個(gè)if結(jié)束
     */

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

    /**
     * 首先檢查是否結(jié)束
     * 沒(méi)有結(jié)束就把結(jié)果value轉(zhuǎn)化為Promise類型
     * 轉(zhuǎn)化成功就執(zhí)行Promise,這里是被onFulfilled調(diào)用,現(xiàn)在又反過(guò)去調(diào)用onFulfilled,形成遞歸。
     * 失敗就調(diào)用onRejected函數(shù)
     */

    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) + """));
    }
  });
}

/**
 * Convert a `yield`ed value into a promise.
 *
 * @param {Mixed} obj
 * @return {Promise}
 * @api private
 */

function toPromise(obj) {
  if (!obj) return obj;
  if (isPromise(obj)) return obj;
  if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
  if ("function" == typeof obj) return thunkToPromise.call(this, obj);
  if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
  if (isObject(obj)) return objectToPromise.call(this, obj);
  return obj;
}

/**
 * Convert a thunk to a promise.
 *
 * @param {Function}
 * @return {Promise}
 * @api private
 */

function thunkToPromise(fn) {
  var ctx = this;
  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);
    });
  });
}

/**
 * Convert an array of "yieldables" to a promise.
 * Uses `Promise.all()` internally.
 *
 * @param {Array} obj
 * @return {Promise}
 * @api private
 */

function arrayToPromise(obj) {
  return Promise.all(obj.map(toPromise, this));
}

/**
 * Convert an object of "yieldables" to a promise.
 * Uses `Promise.all()` internally.
 *
 * @param {Object} obj
 * @return {Promise}
 * @api private
 */

function objectToPromise(obj){
  var results = new obj.constructor();
  var keys = Object.keys(obj);
  var promises = [];
  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);
    else results[key] = obj[key];
  }
  return Promise.all(promises).then(function () {
    return results;
  });

  function defer(promise, key) {
    // predefine the key in the result
    results[key] = undefined;
    promises.push(promise.then(function (res) {
      results[key] = res;
    }));
  }
}

/**
 * Check if `obj` is a promise.
 *
 * @param {Object} obj
 * @return {Boolean}
 * @api private
 */

function isPromise(obj) {
  return "function" == typeof obj.then;
}

/**
 * Check if `obj` is a generator.
 *
 * @param {Mixed} obj
 * @return {Boolean}
 * @api private
 */

function isGenerator(obj) {
  return "function" == typeof obj.next && "function" == typeof obj.throw;
}

/**
 * Check if `obj` is a generator function.
 *
 * @param {Mixed} obj
 * @return {Boolean}
 * @api private
 */
 
function isGeneratorFunction(obj) {
  var constructor = obj.constructor;
  if (!constructor) return false;
  if ("GeneratorFunction" === constructor.name || "GeneratorFunction" === constructor.displayName) return true;
  return isGenerator(constructor.prototype);
}

/**
 * Check for plain object.
 *
 * @param {Mixed} val
 * @return {Boolean}
 * @api private
 */

function isObject(val) {
  return Object == val.constructor;
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87020.html

相關(guān)文章

  • thunkify與co源碼解讀

    開(kāi)頭 首先本文有將近3000字,閱讀可能會(huì)占用你20分鐘左右。 文筆可能不佳,希望能幫助到閱讀此文的人有一些收獲 在進(jìn)行源碼閱讀前首先抱有一個(gè)疑問(wèn),thunk函數(shù)是什么,thunkify庫(kù)又是干什么的,co又是干嘛,它有啥用 程序語(yǔ)言有兩種求值策略 傳名調(diào)用 傳入?yún)?shù)實(shí)際上是傳入函數(shù)體 傳值調(diào)用 函數(shù)體在進(jìn)入的時(shí)候就進(jìn)行運(yùn)算計(jì)算值 編譯器的傳名調(diào)用實(shí)現(xiàn),往往是將參數(shù)放到一個(gè)臨時(shí)函數(shù)之中,再將這個(gè)...

    Tangpj 評(píng)論0 收藏0
  • Koa源碼閱讀筆記(1) -- co

    摘要:正好自己之前也想看的源代碼,所以趁著這個(gè)機(jī)會(huì),一口氣將其讀完。源碼解讀的源代碼十分簡(jiǎn)潔,一共才兩百余行。結(jié)語(yǔ)的源代碼讀取來(lái)不難,但其處理方式卻令人贊嘆。而且閱讀的源代碼,是閱讀源碼的必經(jīng)之路。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理Koa源碼閱讀筆記(4) -- ctx對(duì)象 起...

    taoszu 評(píng)論0 收藏0
  • Koa源碼閱讀筆記(2) -- compose

    摘要:于是抱著知其然也要知其所以然的想法,開(kāi)始閱讀的源代碼。問(wèn)題讀源代碼時(shí),自然是帶著諸多問(wèn)題的。源代碼如下在被處理完后,每當(dāng)有新請(qǐng)求,便會(huì)調(diào)用,去處理請(qǐng)求。接下來(lái)會(huì)繼續(xù)寫(xiě)一些閱讀筆記,因?yàn)榭吹脑创a確實(shí)是獲益匪淺。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理Koa源碼閱讀筆記(4) -...

    roland_reed 評(píng)論0 收藏0
  • Koa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理

    摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理源碼閱讀筆記對(duì)象起因前兩天閱讀了的基礎(chǔ),和中間件的基礎(chǔ)。的前端樂(lè)園原文鏈接源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理Koa源碼閱讀筆記(4) -- ctx對(duì)象 起因 前兩天閱讀了K...

    mrcode 評(píng)論0 收藏0
  • Codeigniter 4.0-dev 版源碼學(xué)習(xí)筆記之一——前言以及 CI 4 預(yù)覽

    摘要:版權(quán)聲明可轉(zhuǎn)載,但不論任何媒體都需要在轉(zhuǎn)載前與本人溝通,并在轉(zhuǎn)載時(shí)注明出處。的各個(gè)核心模塊以模塊名為目錄名分別存儲(chǔ)在這個(gè)目錄下。下一篇文章會(huì)涉及到和。此文可以轉(zhuǎn)載,但轉(zhuǎn)載前需要發(fā)郵件到進(jìn)行溝通,未溝通的均視作侵權(quán)。 寫(xiě)在前面: 為什么選擇開(kāi)發(fā)過(guò)程中的 CI 4 作為源碼解讀版本:(1)首先我選 CI 是因?yàn)樗暗姆€(wěn)定版都是相對(duì)比較輕量小巧的,而且可以認(rèn)為是簡(jiǎn)單的。(2)為什么沒(méi)有選...

    MSchumi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

xavier

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<