coモジュールの使い方と分析
7283 ワード
この記事は個人ブログとSegmentFaultコミュニティの個人欄だけで発表します.転載は出典の個人ブログを明記してください.https://zengxiaotao.github.io SegmentFault個人欄:https://segmentfault.com/blog...
前に書く
nodejsを学んでもちろん学習の枠組みを免れられないで、結局原生のAPIは比較的に低いです.最初に接触したのはKKAです.公式サイトの説明を見てください.
next generation web frame ework for node.js
node.jsに基づく次世代web開発の枠組みです.すごいようです.koaは軽量級のフレームであり、本質的には棚を提供しており、様々な中間部品のカスケード接続によって特定の機能を実現しています.koaはpromiseとgeneratorに助けを借りて、非同期の組み合わせの問題をよく解決しました.
あれは何ですか?koaを勉強するには、coモジュールを勉強する必要があります.coモジュールは非同期をリリースできます.co関数は一つのgenerator関数をパラメータとして受け入れ、関数内部で自動的にyieldを実行します.
ソース分析
使用するcoモジュールのバージョン番号は4.6.0です.
まず、オブジェクトの種類を判断するための関数を見ます.
上記のように、今後valueをプロミケースに包装する時に使います.
coモジュールの出力部分を見てください.
具体的な方法は以下の通りです. toPromise方法を用いて、obj配列の各々を一つのpromise例 に包装する.前の段階の配列に要素が含まれている場合、Promise.all方法はPromise.resove方法を呼び出し、これをpromiseインスタンスに変換する. Promise.all方法は、新たなpromiseの例を返す. promiseの例の配列の中のすべてのインスタンスの状態がresoved状態に変化している場合にのみ、この新しいpromiseのインスタンスの状態がresolovedに変化します.配列の中にpromiseの一例がある状態がrejectiedになると、新しいpromiseのインスタンス状態もすぐにrejectiedに変わります. に戻る新しいpromiseのインスタンス状態がresovedに変化すると、そのresove関数に入ってくるパラメータは、以前の配列の各promiseのインスタンスに対して、resove関数の戻り値からなる配列を呼び出す.戻る新しいpromiseの状態がrejectに変化すると、reject関数に伝えられるパラメータは配列中のpromiseのインスタンスが最初にreject状態に変化する場合、reject関数の戻り値を実行します. 本当に回り道をして、何回も見たら理解できるはずです.
最後に、もしret.valueが対象なら、coモジュールはどうやってpromiseの例に変えますか?
分析し終わったcoのソースコードの全体の実行過程をまとめます.まず、co関数は一つのgenerator関数を受け取り、co関数の内部で実行され、一つのgeneratorのインスタンスを生成する.generatorのnextメソッドを呼び出して、生成されたオブジェクトのvalue属性値にtoPromise方法を使用して、promiseの例を生成し、このpromiseのインスタンスの状態がresolivedに変化した場合、one Fulfilled方法を実行し、再びgeneratorのインスタンスにnext方法を実行し、その後、プロセス全体を繰り返す.エラーが発生した場合、このpromiseのインスタンスによって定義されたreject関数すなわちonReject方法を実行します.
以上は非同期プロセスを同期化することを実現した.
最後にstarを歓迎します
https://github.com/zengxiaotao/zengxiaotao.github.io
前に書く
nodejsを学んでもちろん学習の枠組みを免れられないで、結局原生のAPIは比較的に低いです.最初に接触したのはKKAです.公式サイトの説明を見てください.
next generation web frame ework for node.js
node.jsに基づく次世代web開発の枠組みです.すごいようです.koaは軽量級のフレームであり、本質的には棚を提供しており、様々な中間部品のカスケード接続によって特定の機能を実現しています.koaはpromiseとgeneratorに助けを借りて、非同期の組み合わせの問題をよく解決しました.
あれは何ですか?koaを勉強するには、coモジュールを勉強する必要があります.coモジュールは非同期をリリースできます.co関数は一つのgenerator関数をパラメータとして受け入れ、関数内部で自動的にyieldを実行します.
ソース分析
使用するcoモジュールのバージョン番号は4.6.0です.
まず、オブジェクトの種類を判断するための関数を見ます.
var slice = Array.prototype.slice; // slice
function isObject(val) {
return Object == val.constructor;
}
この二つは言うまでもないでしょう.function isPromise(obj) {
return 'function' == typeof obj.then;
}
対象がpromiseの例かどうかを判断し、判断する根拠も簡単です.アヒルの種類によって、この対象がthenの方法があるかどうかを判断します.function isGenerator(obj) {
return 'function' == typeof obj.next && 'function' == typeof obj.throw;
}
同様に、一つのオブジェクトを判断する場合は、nextメソッドとthrowメソッドがあるかどうかを判断するだけで、generatorのインスタンスです.function isGeneratorFunction(obj) {
var constructor = obj.constructor;
if (!constructor) return false;
if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
return isGenerator(constructor.prototype);
}
generator関数かどうかを判断するには、この関数がGeneratorFunction
関数の例であるかどうかを判断するだけでよい.上記のように、今後valueをプロミケースに包装する時に使います.
coモジュールの出力部分を見てください.
module.exports = co['default'] = co.co = co
したがって、以下の3つの用法は等価である.var co = require('co') // (1)
var co = require('co').co // (2)
var co = require('co').default // (3)
続いて、ヘッディングco
関数です.function co(gen) {
var ctx = this; //
var args = slice.call(arguments, 1) // gen
// promise
return new Promise(function(resolve, reject) {
// generator generator
if (typeof gen === 'function') gen = gen.apply(ctx, args);
// gen generator ,
// promise resolved
if (!gen || typeof gen.next !== 'function') return resolve(gen);
// onFulfilled
onFulfilled();
function onFulfilled(res) {
var ret;
try {
// gen next
ret = gen.next(res);
} catch (e) {
return reject(e);
}
// next
next(ret);
}
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}
function next(ret) {
// gen , ret.done true , promise
// resolved
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value); // value promise
// promise resolve onFulfilled , next , generator next
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のインスタンスを自動的に実行するnext方法を実現しました.次に、coはどのように一つの値をプロミックスに変換しますか?function toPromise(obj) {
if (!obj) return obj; // obj , undefined , false, null
if (isPromise(obj)) return obj; // Promise , promise
if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj); // generator generator
if ('function' == typeof obj) return thunkToPromise.call(this, obj); // thunk
if (Array.isArray(obj)) return arrayToPromise.call(this, obj); //
if (isObject(obj)) return objectToPromise.call(this, obj); // plain object
return obj; // , 。
}
じゃ、各関数を順番に見てください.function thunkToPromise(fn) {
var ctx = this; //
// promise
return new Promise(function (resolve, reject) {
// thunk
// thunk
fn.call(ctx, function (err, res) {
// thunk
// promise rejected , reject , co onRejected ,
if (err) return reject(err);
//
if (arguments.length > 2) res = slice.call(arguments, 1);
// promise resolved , resolve , onFulfilled
resolve(res);
});
});
}
したがって、要約すると、このthunk関数はgenerator yieldの後にthunk関数があるということです.このthunk関数はパラメータとしてフィードバックパラメータを受け入れています.function arrayToPromise(obj) {
// Promise.all promise
// obj , promise
// promise resolved
// promise resloved
// resolve promise
return Promise.all(obj.map(toPromise, this));
}
同様に、Objが配列である場合、yield文の後の表現の値が配列である場合、Promise.all方法を実行して、配列の各項目をpromiseの例に変えます.具体的な方法は以下の通りです.
最後に、もしret.valueが対象なら、coモジュールはどうやってpromiseの例に変えますか?
function objectToPromise(obj){
//
var results = new obj.constructor();
// obj
var keys = Object.keys(obj);
// promise
var promises = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var promise = toPromise.call(this, obj[key]); // promise
if (promise && isPromise(promise)) defer(promise, key);
else results[key] = obj[key];
}
// promise.all
return Promise.all(promises).then(function () {
return results; // results onFulfilled
});
//
// promise resolve
// promise promises
function defer(promise, key) {
// predefine the key in the result
results[key] = undefined;
promises.push(promise.then(function (res) {
results[key] = res; // promise resolve
}));
}
}
締め括りをつける分析し終わったcoのソースコードの全体の実行過程をまとめます.まず、co関数は一つのgenerator関数を受け取り、co関数の内部で実行され、一つのgeneratorのインスタンスを生成する.generatorのnextメソッドを呼び出して、生成されたオブジェクトのvalue属性値にtoPromise方法を使用して、promiseの例を生成し、このpromiseのインスタンスの状態がresolivedに変化した場合、one Fulfilled方法を実行し、再びgeneratorのインスタンスにnext方法を実行し、その後、プロセス全体を繰り返す.エラーが発生した場合、このpromiseのインスタンスによって定義されたreject関数すなわちonReject方法を実行します.
以上は非同期プロセスを同期化することを実現した.
最後にstarを歓迎します
https://github.com/zengxiaotao/zengxiaotao.github.io