継続ローカルストレージ変数を使用してノードコードを簡素化
16191 ワード
TLドクター
cls.anythingYouLike = somethingElse
そして、それは現在の要求によって呼ばれるコードのどこにでもセットされて、見つけられます、しかし、他の要求と干渉しません.audit
それは誰が現在のユーザーが知っているし、コンテキストの多くを渡す必要がなく、どこでもそれらを呼び出すことができます. function someDeepRoutine(param) {
// Audit that the current user has accessed this function
// Without us having to explicitly pass lots of identity
// variables...
cls.audit("deepRoutineExecuted", {param})
}
npm -i simple-continuation-local-storage
. 考え
我々はフロントエンド上のアプリケーションの状態を管理する方法のすべての種類がありますが、サーバーになると私たちは失われた自分自身を見つけることができるパラメータやコンテキスト変数の質量は、何かの場合に何かを介して転送する必要があります後に何かが必要です.
これは、さまざまなユーザーに対して並列処理をしているものに対して、グローバルな状態を持つことができないからです.最高の状態でコンテキストを作成し、それを関連付けることができますが、継続的なローカルストレージを使用して簡単に方法があります.
CLSは、スレッドローカルのストレージのようなビットで、特にスレッドによって所有されているので、名前が付けられます.現在の実行コンテキストのスコープです.だから、どのように多くの継続がサーバーを介して流れている、関係なく、それぞれの独自のコピーを持っている.
今のところ、これの実装の数があったが、私はそれらをすべて複雑すぎる(名前空間などを取得)を使用し、いくつかのコードを続けている-私は何かを“グローバル”の変数のような感じが欲しいが私のために管理されます.
私のサーバはすべて今すぐに実行されますが、私たちによって引き起こされる小さなオーバーヘッドがありますが
async_hooks
あなたが“継続”を作成するたびに呼び出されます-あなたはすぐにコードがかなりタイトで表示されます.CLSライブラリの使用
CLSを使用するには、それをインストールし、それを必要とするだけで、リクエスト応答をラップするために$ initメソッドを使用します.その後のように
global
でも知ってる.local
!const events = require('event-bus');
const cls = require('simple-continuation-local-storage')
app.get('/somepath', cls.$init(async function(req,res) {
cls.jobs = 0;
cls.req = req;
cls.anything = 1;
await someOtherFunction();
res.status(200).send(await doSomeWork());
})
async someOtherFunction() {
await events.raiseAsync('validate-user');
}
events.on('validate-user', async function() {
const token = cls.req.query.token;
cls.authenticated = await validateToken(token);
});
async validateToken(token) {
await new Promise(resolve=>setTimeout(resolve, 100));
return true;
}
async doSomeWork() {
cls.jobs++;
await new Promise(resolve=>setTimeout(resolve, 1000));
return [{work: "was very hard"}];
}
あなたが見ることができるように、それはちょうどあなたがグローバルを使用していたようです.何か-しかし、それはすべての要求に一意になるだろう.動作方法
使用するCLS
async_hooks
ノードの機能は、新しいasyncコンテキストが行われるたびに通知することができます.また、プロキシを使用して、我々は自然と感じるように期待して動作する甘いシンプルなインターフェイスを持つことができます.const hooks = require( 'async_hooks' )
const cls = {}
let current = null
const HOLD = "$HOLD"
hooks
.createHook( {
init ( asyncId, type, triggerId ) {
let existing = cls[ triggerId ] || {}
cls[ asyncId ] = existing[HOLD] ? existing : { ...existing, _parent: existing}
},
before ( id ) {
current = cls[ id ] = cls[id] || {}
},
after () {
current = null
},
destroy ( id ) {
delete cls[ id ]
},
} )
.enable()
フックは4つのコールバックを持ちます.init
新しいコンテキストが作成されたときに呼び出されます.これは、asyncコールを行うたびに、毎回返しますイン
init
現在の状態を表す現在のPOJOを取得します.それから、$ hold = trueメンバーがあるならば、我々はちょうどそれを子供に沿って送ります.それがそうしないならば、我々はそれの浅いコピーをして、それを送ります.このサーバーのすべては、このフックを通して実行しています-私たちは、ただ一つの要求または他のエントリポイントのメンバーを通して後方に、そして、前方に内容を本当に共有し始めるだけです.言い換えると、要求が終わるまで、どんな関数でもいつでも見つけることができる値を設定することができます.あれ
cls.$init(fn)
上記の関数で設定します.反対の
init
is destroy
- この時点で我々は再び見られることはありません我々のコンテキストをスローすることができます.before
コンテキストが入力される前に呼び出されます-コードが実行される直前にinit
. after
ちょっとクリア.それはすべてそこにある!
その後、ファンシープロキシのものだけで
cls
好きになるglobal
.function getCurrent () {
return current
}
module.exports = new Proxy( getCurrent, {
get ( obj, prop ) {
if ( prop === '$hold' ) return function(hold) {
current[HOLD] = !!hold
}
if( prop=== '$init') return function(fn) {
current && (current[HOLD] = true)
if(fn) {
return function(...params) {
current && (current[HOLD] = true)
return fn(...params)
}
}
}
if ( current ) {
return current[ prop ]
}
},
set ( obj, prop, value ) {
if ( current ) {
current[ prop ] = value
}
return true
},
has ( obj, prop ) {
return prop in current
},
} )
このプロパティを設定すると、現在のコンテクストで現在のコンテキストに設定されます.ゲットアンドhas
は逆です.あなたは電話することができます
cls()
現在のオブジェクトを取得するにはデモ
下のサンドボックスは、これを実装し、非常に退屈なページのための急行サーバーを提供します.あなたが通過しないならば?トークン=マジック?token = nosomagicその後、それは認証されません.それ以外の場合は、何が起こるかを制御する許可定義でCLSをどのように飾るかを見ることができます.
Reference
この問題について(継続ローカルストレージ変数を使用してノードコードを簡素化), 我々は、より多くの情報をここで見つけました https://dev.to/miketalbot/simplify-your-node-code-with-continuation-local-storage-variables-4b3kテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol