co源码解读
最近在學習使用Koa.在看官網的例子的時候時候看到它的中間件的級聯模式是通過生成器實現的,之后了解到Koa的級聯是通過Co這個庫實現的,下面就是對這個庫的代碼的主要流程的部分解讀
1.生成器基礎
2.代碼解讀
1.生成器基礎
這個是infoq的深入淺出ES6中生成器的一章 ? 生成器基礎
?
可以通過下面的代碼片段去大致的理解Co函數的執行過程 ?生成器可以通過next來實現任務的串行執行 ?next方法返回一個對象 有value屬性(yield執行的值) done 是否還有未執行的yield邏輯 同時還能將參數通過next進行傳遞 供下面的邏輯調用
?
function *test() {var x = yield 1;yield console.log(x); }var a = test(); var temp = a.next(); a.next(temp.value) //1 View Code?
2. 代碼解讀部分
function objectToPromise(obj){var results = new obj.constructor();var keys = Object.keys(obj); //Object.keys()返回一個對象所有可枚舉屬性的數組var promises = [];//保存對象中promise運行的結果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);//將原對象屬性中Promise的與數組關聯else results[key] = obj[key];}return Promise.all(promises).then(function () {return results;});//Promise接受一個Promise對象的數組作為參數 當數組里面全部變成resolve或者reject狀態function defer(promise, key) {// predefine the key in the resultresults[key] = undefined;promises.push(promise.then(function (res) {results[key] = res; //romise的then方法不僅僅是注冊resolve的回調 還會將回調函數的返回值進行變換 返回promsie對象}));} } View Code?Co將中間的結果和函數都進行了Promise的封裝 ?主要看下這個objectToPromise(obj) ?功能就是將一個對象轉換為Promise對象 這里需要理解這兩個方法 Promise.all ?它接受一個Promsie數組 當數組中全部為resolve時,它就變成resolve,當其中有一個出現reject的時候,就進入reject狀態。可以通過下面的代碼簡單的理解它的使用
var promise1 = new Promise(function(resolve,reject){resolve(1); }); var promise2 = new Promise(function(resolve,reject){resolve(2); }); Promise.all([promise1,promise2]).then(function(){console.log('ok'); }); View Code接下來說說這個defer(promise,key) 它的功能就是將原來對象的值裝換為promise之后,通過數組的方式傳遞給外部
function defer(promise, key) {// predefine the key in the resultresults[key] = undefined;promises.push(promise.then(function (res) {results[key] = res; promise的then方法不僅僅是注冊resolve的回調 還會將回調函數的返回值進行變換 返回promsie對象}));} View Codepromise.then ?這個方法是返回一個Promise對象 這樣通過then方法將所有鍵值的執行結果都轉換為Promsie對象 在通過數組的方式傳遞給外部 當所有鍵值執行都為resolve的時候 就將整體的結果返回給外部 也就完成了對obj對象的封裝。
下面就來理解下Co函數
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/180return new Promise(function(resolve, reject) {if (typeof gen === 'function') gen = gen.apply(ctx, args);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(res);} catch (e) {return reject(e);}next(ret);return null;}/*** @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*///co函數的核心就是這個next理解 通過next傳遞將上一個generator執行的結果往下傳遞并且進行了Promise的封裝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) + '"'));}}); } View Code參考 ?Generator與異步編程? ?Co
?
?
?轉載于:https://www.cnblogs.com/tiantianwaigong/p/6441723.html
總結
- 上一篇: 理解原理的重要性 - 论PostgreS
- 下一篇: 第一个程序实现登录功能,密码输错三次封账