摘要:提取函數(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
開(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è)...
摘要:正好自己之前也想看的源代碼,所以趁著這個(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ì)象 起...
摘要:于是抱著知其然也要知其所以然的想法,開(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) -...
摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(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...
摘要:版權(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)有選...
閱讀 2076·2021-11-11 16:54
閱讀 1054·2021-10-12 10:12
閱讀 392·2019-08-30 15:43
閱讀 656·2019-08-29 13:15
閱讀 1086·2019-08-29 13:12
閱讀 1537·2019-08-26 12:09
閱讀 1668·2019-08-26 10:24
閱讀 2274·2019-08-26 10:15