摘要:正好自己之前也想看的源代碼,所以趁著這個機會,一口氣將其讀完。源碼解讀的源代碼十分簡潔,一共才兩百余行。結(jié)語的源代碼讀取來不難,但其處理方式卻令人贊嘆。而且閱讀的源代碼,是閱讀源碼的必經(jīng)之路。
起因本筆記共四篇
Koa源碼閱讀筆記(1) -- co
Koa源碼閱讀筆記(2) -- compose
Koa源碼閱讀筆記(3) -- 服務(wù)器の啟動與請求處理
Koa源碼閱讀筆記(4) -- ctx對象
在7月23號時,我參加了北京的NodeParty。其中第一場演講就是深入講解Koa。
由于演講只有一個小時,講不完Koa的原理。于是在聽的時候覺得并不是很滿足,遂開始自己翻看源代碼。
而Koa1是基于ES6的generator的。其在Koa1中的運行依賴于co。
正好自己之前也想看co的源代碼,所以趁著這個機會,一口氣將其讀完。
關(guān)于co,其作者的介紹很是簡單。
The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)
而co的意義,則在于使用generator函數(shù),解決了JavaScript的回調(diào)地獄問題。
源碼解讀co的源代碼十分簡潔,一共才兩百余行。而且里面注釋到位,所以閱讀起來的難度還是不大的。
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) { // 啟動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的對象 // gen.next(res),則是向generator函數(shù)傳參數(shù),作為yield的返回值 /** * yield句本身沒有返回值,或者說總是返回undefined。 * next方法可以帶一個參數(shù),該參數(shù)就會被當作上一個yield語句的返回值。 * [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) { // 如果這個generator函數(shù)完成了,返回最終的值 // 在所有yield完成后,調(diào)用next()會返回{value: undefined, done: true} // 所以需要手動return一個值。這樣最后的value才不是undefined if (ret.done) return resolve(ret.value); // 未完成則統(tǒng)一交給toPromise函數(shù)去處理 // 這里的ret.value實際是 yield 后面的那個(對象|函數(shù)|值) 比如 yield "hello", 此時的value則是 "hello" var value = toPromise.call(ctx, ret.value); // 這里value.then(onFulfilled, onRejected),實際上已經(jīng)調(diào)用并傳入了 onFulfilled, onRejected 兩個參數(shù)。 // 因為非這些對象,無法調(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的運行機制
看完了源代碼,對generator函數(shù)有更深的理解,也理解了co的運行機制。
自動執(zhí)行g(shù)enerator首先解決的問題則是自動執(zhí)行generator函數(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傳入一個generator函數(shù)后,co會將其自動啟動。然后調(diào)用onFulfilled函數(shù)。
在onFulfilled函數(shù)內(nèi)部,首先則是獲取next的返回值。交由next函數(shù)處理。
而next函數(shù)則首先判斷是否完成,如果這個generator函數(shù)完成了,返回最終的值。
否則則將yield后的值,轉(zhuǎn)換為Promise。
最后,通過Promise的then,并將onFulfilled函數(shù)作為參數(shù)傳入。
if (value && isPromise(value)) { return value.then(onFulfilled, onRejected); }
而在generator中,yield句本身沒有返回值,或者說總是返回undefined。
而next方法可以帶一個參數(shù),該參數(shù)就會被當作上一個yield語句的返回值。
同時通過onFulfilled函數(shù),則可以實現(xiàn)自動調(diào)用。
這也就能解釋為什么co基于Promise。且能自動執(zhí)行了。
co的源代碼讀取來不難,但其處理方式卻令人贊嘆。
而且generator函數(shù)的使用,對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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86468.html
摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動與請求處理源碼閱讀筆記對象起因前兩天閱讀了的基礎(chǔ),和中間件的基礎(chǔ)。的前端樂園原文鏈接源碼閱讀筆記服務(wù)器啟動與請求處理 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動與請求處理Koa源碼閱讀筆記(4) -- ctx對象 起因 前兩天閱讀了K...
摘要:于是抱著知其然也要知其所以然的想法,開始閱讀的源代碼。問題讀源代碼時,自然是帶著諸多問題的。源代碼如下在被處理完后,每當有新請求,便會調(diào)用,去處理請求。接下來會繼續(xù)寫一些閱讀筆記,因為看的源代碼確實是獲益匪淺。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動與請求處理Koa源碼閱讀筆記(4) -...
摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動與請求處理源碼閱讀筆記對象起因前兩天終于把自己一直想讀的源代碼讀了一遍。首先放上關(guān)鍵的源代碼在上一篇源碼閱讀筆記服務(wù)器啟動與請求處理中,我們已經(jīng)分析了的作用。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動與請求處理Koa源碼閱讀筆記(4...
摘要:接上次挖的坑,對相關(guān)的源碼進行分析第一篇。和同為一批人進行開發(fā),與相比,顯得非常的迷你。在接收到一個請求后,會拿之前提到的與來創(chuàng)建本次請求所使用的上下文。以及如果沒有手動指定,會默認指定為。 接上次挖的坑,對koa2.x相關(guān)的源碼進行分析 第一篇。 不得不說,koa是一個很輕量、很優(yōu)雅的http框架,尤其是在2.x以后移除了co的引入,使其代碼變得更為清晰。 express和ko...
摘要:返回的結(jié)果是一個對象,類似于表示本次后面執(zhí)行之后返回的結(jié)果。對象用于一個異步操作的最終完成或失敗及其結(jié)果值的表示簡單點說就是處理異步請求。源碼分析主要脈絡(luò)函數(shù)調(diào)用后,返回一個實例。參考鏈接解釋對象的用法的源碼及其用法 本文始發(fā)于我的個人博客,如需轉(zhuǎn)載請注明出處。為了更好的閱讀體驗,可以直接進去我的個人博客看。 前言 知識儲備 閱讀本文需要對Generator和Promise有一個基本的...
閱讀 1785·2021-11-15 11:37
閱讀 3064·2021-11-04 16:05
閱讀 1925·2021-10-27 14:18
閱讀 2756·2021-08-12 13:30
閱讀 2500·2019-08-29 14:18
閱讀 2086·2019-08-29 13:07
閱讀 2025·2019-08-27 10:54
閱讀 2727·2019-08-26 12:15