摘要:提取函數方便使用暴露把函數包起來,返回執行不帶參數的函數,返回如果是函數,直接執行,指定作域判斷等價于,判斷函數是否執行完根據返回值是否,執行完就通過返回,外部將會執行函數帶參數用于修改上一次結果,引擎會忽略第一次執行時參數用于捕獲錯誤執行
/** * 提取slice()函數方便使用 */ var slice = Array.prototype.slice; /** * 暴露 `co`. */ module.exports = co["default"] = co.co = co; /** * 把generator函數 `fn` 包起來,返回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)); } }; /** * 執行不帶參數的generator函數,返回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) { //如果是函數,直接執行,apply指定作域 if (typeof gen === "function") gen = gen.apply(ctx, args); // 判斷等價于 !(gen && typeof gen.next === "function"),判斷generator函數是否執行完(根據返回值是否Iterator Object),執行完就通過resolve返回,外部將會執行`.then`函數 if (!gen || typeof gen.next !== "function") return resolve(gen); onFulfilled(); /** * .next帶參數用于修改上一次yield結果,V8引擎會忽略第一次執行時參數 * try/catch 用于捕獲錯誤 * 執行完的結果交給自定義的next函數,res結構應該是 {value, done} */ function onFulfilled(res) { var ret; try { ret = gen.next(res); } catch (e) { return reject(e); } next(ret); return null; } /** * 自己捕獲err * 注意,這里是調用generator遍歷器上的throw方法 * 一個generator執行出錯后就不再執行,返回{value:undefined, done: true},故這里調用next函數會在第一個if結束 */ function onRejected(err) { var ret; try { ret = gen.throw(err); } catch (e) { return reject(e); } next(ret); } /** * 首先檢查是否結束 * 沒有結束就把結果value轉化為Promise類型 * 轉化成功就執行Promise,這里是被onFulfilled調用,現在又反過去調用onFulfilled,形成遞歸。 * 失敗就調用onRejected函數 */ 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; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87020.html
開頭 首先本文有將近3000字,閱讀可能會占用你20分鐘左右。 文筆可能不佳,希望能幫助到閱讀此文的人有一些收獲 在進行源碼閱讀前首先抱有一個疑問,thunk函數是什么,thunkify庫又是干什么的,co又是干嘛,它有啥用 程序語言有兩種求值策略 傳名調用 傳入參數實際上是傳入函數體 傳值調用 函數體在進入的時候就進行運算計算值 編譯器的傳名調用實現,往往是將參數放到一個臨時函數之中,再將這個...
摘要:正好自己之前也想看的源代碼,所以趁著這個機會,一口氣將其讀完。源碼解讀的源代碼十分簡潔,一共才兩百余行。結語的源代碼讀取來不難,但其處理方式卻令人贊嘆。而且閱讀的源代碼,是閱讀源碼的必經之路。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務器の啟動與請求處理Koa源碼閱讀筆記(4) -- ctx對象 起...
摘要:于是抱著知其然也要知其所以然的想法,開始閱讀的源代碼。問題讀源代碼時,自然是帶著諸多問題的。源代碼如下在被處理完后,每當有新請求,便會調用,去處理請求。接下來會繼續寫一些閱讀筆記,因為看的源代碼確實是獲益匪淺。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務器の啟動與請求處理Koa源碼閱讀筆記(4) -...
摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務器啟動與請求處理源碼閱讀筆記對象起因前兩天閱讀了的基礎,和中間件的基礎。的前端樂園原文鏈接源碼閱讀筆記服務器啟動與請求處理 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務器の啟動與請求處理Koa源碼閱讀筆記(4) -- ctx對象 起因 前兩天閱讀了K...
摘要:版權聲明可轉載,但不論任何媒體都需要在轉載前與本人溝通,并在轉載時注明出處。的各個核心模塊以模塊名為目錄名分別存儲在這個目錄下。下一篇文章會涉及到和。此文可以轉載,但轉載前需要發郵件到進行溝通,未溝通的均視作侵權。 寫在前面: 為什么選擇開發過程中的 CI 4 作為源碼解讀版本:(1)首先我選 CI 是因為它之前的穩定版都是相對比較輕量小巧的,而且可以認為是簡單的。(2)為什么沒有選...
閱讀 2058·2021-11-11 16:54
閱讀 1039·2021-10-12 10:12
閱讀 377·2019-08-30 15:43
閱讀 646·2019-08-29 13:15
閱讀 1075·2019-08-29 13:12
閱讀 1524·2019-08-26 12:09
閱讀 1655·2019-08-26 10:24
閱讀 2251·2019-08-26 10:15