国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Koa源碼閱讀筆記(1) -- co

taoszu / 2041人閱讀

摘要:正好自己之前也想看的源代碼,所以趁著這個(gè)機(jī)會(huì),一口氣將其讀完。源碼解讀的源代碼十分簡(jiǎn)潔,一共才兩百余行。結(jié)語(yǔ)的源代碼讀取來不難,但其處理方式卻令人贊嘆。而且閱讀的源代碼,是閱讀源碼的必經(jīng)之路。

本筆記共四篇
Koa源碼閱讀筆記(1) -- co
Koa源碼閱讀筆記(2) -- compose
Koa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理
Koa源碼閱讀筆記(4) -- ctx對(duì)象

起因

在7月23號(hào)時(shí),我參加了北京的NodeParty。其中第一場(chǎng)演講就是深入講解Koa。
由于演講只有一個(gè)小時(shí),講不完Koa的原理。于是在聽的時(shí)候覺得并不是很滿足,遂開始自己翻看源代碼。
而Koa1是基于ES6的generator的。其在Koa1中的運(yùn)行依賴于co。
正好自己之前也想看co的源代碼,所以趁著這個(gè)機(jī)會(huì),一口氣將其讀完。

co

關(guān)于co,其作者的介紹很是簡(jiǎn)單。

The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)

而co的意義,則在于使用generator函數(shù),解決了JavaScript的回調(diào)地獄問題

源碼解讀

co的源代碼十分簡(jiǎn)潔,一共才兩百余行。而且里面注釋到位,所以閱讀起來的難度還是不大的。
co的核心代碼如下(已加上自己的注釋):

/**
 * Execute the generator function or a generator
 * and return a 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) {
    // 啟動(dòng)generator函數(shù)。
    if (typeof gen === "function") gen = gen.apply(ctx, args);
    // 如果gen不存在或者gen.next不是函數(shù)(非generator函數(shù))則返回空值
    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 return的對(duì)象
        // gen.next(res),則是向generator函數(shù)傳參數(shù),作為yield的返回值
        /**
         * yield句本身沒有返回值,或者說總是返回undefined。
         * next方法可以帶一個(gè)參數(shù),該參數(shù)就會(huì)被當(dāng)作上一個(gè)yield語(yǔ)句的返回值。
         * [next方法的參數(shù)](http://es6.ruanyifeng.com/#docs/generator#next方法的參數(shù))
         */
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      // 在這兒,每完成一次yield,便交給next()處理
      next(ret);
    }

    /**
     * @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
     */

    function next(ret) {
      // 如果這個(gè)generator函數(shù)完成了,返回最終的值
      // 在所有yield完成后,調(diào)用next()會(huì)返回{value: undefined, done: true}
      // 所以需要手動(dòng)return一個(gè)值。這樣最后的value才不是undefined
      if (ret.done) return resolve(ret.value);
      // 未完成則統(tǒng)一交給toPromise函數(shù)去處理
      // 這里的ret.value實(shí)際是 yield 后面的那個(gè)(對(duì)象|函數(shù)|值) 比如 yield "hello", 此時(shí)的value則是 "hello"
      var value = toPromise.call(ctx, ret.value);
      // 這里value.then(onFulfilled, onRejected),實(shí)際上已經(jīng)調(diào)用并傳入了 onFulfilled, onRejected 兩個(gè)參數(shù)。
      // 因?yàn)榉沁@些對(duì)象,無法調(diào)用then方法。也就無法使用onFulfilled
      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;
}
co的運(yùn)行機(jī)制

看完了源代碼,對(duì)generator函數(shù)有更深的理解,也理解了co的運(yùn)行機(jī)制。

自動(dòng)執(zhí)行g(shù)enerator

首先解決的問題則是自動(dòng)執(zhí)行generator函數(shù)是如何實(shí)現(xiàn)的。
這兒的核心部分則在于:

function co(gen) {
  if (typeof gen === "function") gen = gen.apply(ctx, args);
  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傳入一個(gè)generator函數(shù)后,co會(huì)將其自動(dòng)啟動(dòng)。然后調(diào)用onFulfilled函數(shù)。
onFulfilled函數(shù)內(nèi)部,首先則是獲取next的返回值。交由next函數(shù)處理。
next函數(shù)則首先判斷是否完成,如果這個(gè)generator函數(shù)完成了,返回最終的值。
否則則將yield后的值,轉(zhuǎn)換為Promise。
最后,通過Promise的then,并將onFulfilled函數(shù)作為參數(shù)傳入。

if (value && isPromise(value)) {
  return value.then(onFulfilled, onRejected);
}

而在generator中,yield句本身沒有返回值,或者說總是返回undefined。
而next方法可以帶一個(gè)參數(shù),該參數(shù)就會(huì)被當(dāng)作上一個(gè)yield語(yǔ)句的返回值。
同時(shí)通過onFulfilled函數(shù),則可以實(shí)現(xiàn)自動(dòng)調(diào)用。
這也就能解釋為什么co基于Promise。且能自動(dòng)執(zhí)行了。

結(jié)語(yǔ)

co的源代碼讀取來不難,但其處理方式卻令人贊嘆。
而且generator函數(shù)的使用,對(duì)ES7中的Async/Await的產(chǎn)生,起了關(guān)鍵作用。
正如其作者TJ在co的說明文檔中所說的那樣:

Co is a stepping stone towards ES7 async/await.

雖然說我沒用過co,只使用過Async/Await
但如今的Async/Await,使用babel,啟用transform-async-to-generator插件,轉(zhuǎn)譯后,也是編譯為generator函數(shù)。
所以了解一下,還是有好處的。而且閱讀co的源代碼,是閱讀koa1源碼的必經(jīng)之路。

前端路漫漫,且行且歌。

最后附上本人博客地址和原文鏈接,希望能與各位多多交流。

Lxxyx的前端樂園
原文鏈接:Koa源碼閱讀筆記(1) -- co

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86468.html

相關(guān)文章

  • Koa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理

    摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理源碼閱讀筆記對(duì)象起因前兩天閱讀了的基礎(chǔ),和中間件的基礎(chǔ)。的前端樂園原文鏈接源碼閱讀筆記服務(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
  • Koa源碼閱讀筆記(2) -- compose

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

    roland_reed 評(píng)論0 收藏0
  • Koa源碼閱讀筆記(4) -- ctx對(duì)象

    摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理源碼閱讀筆記對(duì)象起因前兩天終于把自己一直想讀的源代碼讀了一遍。首先放上關(guān)鍵的源代碼在上一篇源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理中,我們已經(jīng)分析了的作用。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理Koa源碼閱讀筆記(4...

    ityouknow 評(píng)論0 收藏0
  • koa源碼閱讀[1]-koakoa-compose

    摘要:接上次挖的坑,對(duì)相關(guān)的源碼進(jìn)行分析第一篇。和同為一批人進(jìn)行開發(fā),與相比,顯得非常的迷你。在接收到一個(gè)請(qǐng)求后,會(huì)拿之前提到的與來創(chuàng)建本次請(qǐng)求所使用的上下文。以及如果沒有手動(dòng)指定,會(huì)默認(rèn)指定為。 接上次挖的坑,對(duì)koa2.x相關(guān)的源碼進(jìn)行分析 第一篇。 不得不說,koa是一個(gè)很輕量、很優(yōu)雅的http框架,尤其是在2.x以后移除了co的引入,使其代碼變得更為清晰。 express和ko...

    vibiu 評(píng)論0 收藏0
  • co源碼分析及其實(shí)踐

    摘要:返回的結(jié)果是一個(gè)對(duì)象,類似于表示本次后面執(zhí)行之后返回的結(jié)果。對(duì)象用于一個(gè)異步操作的最終完成或失敗及其結(jié)果值的表示簡(jiǎn)單點(diǎn)說就是處理異步請(qǐng)求。源碼分析主要脈絡(luò)函數(shù)調(diào)用后,返回一個(gè)實(shí)例。參考鏈接解釋對(duì)象的用法的源碼及其用法 本文始發(fā)于我的個(gè)人博客,如需轉(zhuǎn)載請(qǐng)注明出處。為了更好的閱讀體驗(yàn),可以直接進(jìn)去我的個(gè)人博客看。 前言 知識(shí)儲(chǔ)備 閱讀本文需要對(duì)Generator和Promise有一個(gè)基本的...

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

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

0條評(píng)論

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