NodeJs中async-honksモジュールの使用を学びます.

15671 ワード

Async HooksはNode 8新出来の特性であり、NodeJsにおける非同期資源のライフサイクルを追跡するAPIを提供しています.NodeJs内蔵モジュールに属しています.直接参照できます.

let asycnHooks = require('async_hooks');

async_を導入したのはなぜですか?Hooksモジュールは、非同期呼出において、非同期呼出しの処理ロジックと関係を正確に追跡することが難しいからです.async_これらの問題は主に以下の機能と特性を提供します.
  • の各関数はいずれも一つのコンテキストを提供します.私たちはこれをasync scopeと呼びます.
  • 各async scopeにはasyncIdがあります.現在のasync scopeのマークです.同じasync scopeの中でasyncIdはきっと同じです.最外層のasyncIdは1で、各非同期資源は作成時にasyncIdの全量が増加します.
  • 各async scopeには一つのトリガーAyncIdがあります.現在の関数はそのasync scopeによって生成されたものです.
  • asyncIdとtrigger AyncIdを通じて、非同期全体の呼び出し関係とリンクを簡単に追跡することができます.
  • 私たちはasync_を通過できます.各非同期リソースがライフサイクルで発生するinit/before/after/destory/promiseResoliveなどの関連イベントに関する傍受関数を登録します.
  • 同じasync scopeは何度も呼び出されて実行されるかもしれません.何回実行しても、asyncIdは必ず同じです.モニター関数を通じて、私たちはその実行回数と時間とオンライン文の関係を追跡しやすいです.
  • execution AsyncIdとtrigger AryncId
    async_Oksモジュールは、現在のコンテキストのasyncIdとtrigger AryncId関数を提供し、trigger AcyncId関数を取得する.
    const async_hooks = require('async_hooks');
    const fs = require('fs');
    console.log('global.asyncId:', async_hooks.executionAsyncId());  // global.asyncId: 1
    console.log('global.triggerAsyncId:', async_hooks.triggerAsyncId()); // global.triggerAsyncId: 0
    fs.open('./app.js', 'r', (err, fd) => {
        console.log('fs.open.asyncId:', async_hooks.executionAsyncId()); // fs.open.asyncId: 7
        console.log('fs.open.triggerAsyncId:', async_hooks.triggerAsyncId()); // fs.open.triggerAsyncId: 1
    });
    
    上記の印刷結果によって、全体のasyncIdは1で、fs.openコール関数のasyncIdは7で、trigger AryncIdは1であることが分かります.fs.openという非同期リソースは、グローバルな呼び出しによってトリガされることが分かる.
    async_Hook(calbacks)
    私たちはasync_を使うことができます.Hookは、非同期リソースのフックを作成し、非同期リソースライフサイクルで発生する可能性のあるイベントに関するいくつかのコールバック関数をasync_として登録します.Hookの入力.非同期リソースが作成されるたびに、これらのフック関数がトリガされます.
    const async_hooks = require('async_hooks');
    const asyncHook = async_hooks.createHook({
      init(asyncId, type, triggerAsyncId, resource) { },
      destroy(asyncId) { }
    });
    asyncHook.enable();   //   enable         
    
    現在createHook関数は5種類のHook Callbacksを受け入れることができます.
    init(asyncId,type,trigger AyncId,reource)
    initコールバック関数は、非同期リソースの初期化時にトリガされ、そのパラメータは以下のように解釈される.
  • asyncId:各非同期リソースは、一意のフラグ
  • を生成します.
  • type:非同期資源のタイプは、一般的には資源の構造関数の名前です.async_を参照できるものがありますか?公式文書
  • trigger AyncId:現在非同期リソースが作成された対応するasync scopeをトリガするasyncId
  • を表します.
  • resource:初期化された非同期リソースオブジェクトを表す
  • before(asyncid)
    beforeコールバック関数は、一般的にasyncIdに対応する非同期のリソース操作が完了したら、コールバックを実行する前に呼び出され、beforeコールバック関数は複数回実行されるかもしれません.
    after(asyncid)
    afterコールバック関数は、通常、非同期リソースがコールバック関数を実行した後に呼び出されます.コールバック関数の実行中に捕獲されていない異常が発生すると、afterイベントは「uncaghtException」イベントをトリガした後に呼び出されます.
    destroy(asyncid)
    ASyncId対応の非同期リソースが破壊された時に呼び出します.一部の非同期資源の廃棄はごみ回収メカニズムに依存しますので、メモリ漏れの原因で、destoryイベントはいつまでもトリガされないかもしれません.
    promiseResolive(asyncId)
    Promiseコンストラクタにおけるreovale関数が実行されると、promiseResoliveイベントがトリガされる.いくつかの場合、レスリング関数は暗黙的に実行されます.例えば、then関数は新しいPromiseに戻ります.この時も呼び出されます.
    次の表式は2回のpromiseResoveイベントをトリガします.最初はnew Promise()の時に明示的に実行されるresove関数です.2番目は.then関数のコールバックで暗黙的に実行されるresove関数です.
    new Promise((resolve) => resolve(true)).then((a) => {});
    
    
    Promiseの実行追跡
    V 8のpromise introsspection APIはasyncIdを取得するための実行コストが高いので、デフォルトではPromiseに新しいasyncidを割り当てません.つまりデフォルトの状況では、promisesやasync/awaitを使うと、現在のコンテキストが正しいasyncIdやtriggerIdが得られません.でも大丈夫です.async_を実行します.Hook(calbacks).enable()関数強制オープンはPromiseにasyncIdを割り当てます:
    const ah = require('async_hooks');
    ah.createHook({ init() {} }).enable(); // PromiseHooks       
    Promise.resolve(1729).then(() => {
      console.log(`asyncId ${ah.executionAsyncId()} triggerId ${ah.triggerAsyncId()}`);
    });
    
    
    なお、beforeとafterイベントのフック関数はPromiseのチェーン呼び出し時にのみ触発され、つまり.then/catch関数で生成されたPromise時にのみ触発され、他のところではinitとpromiseResoliveフックイベント関数のみがトリガされます.
    だから、私達がどのように操作する時:
    new Promise((resolve) => resolve(true)).then((a) => {});
    
    それぞれトリガされるイベントの流れは以下の通りです.
  • asyncId=5のinitイベント関数
  • asyncId=5のpromiseResoliveイベント関数
  • asyncId=6のinitイベント関数
  • asyncId=6のbeforeイベント関数
  • asyncId=6のpromiseResololeイベント関数
  • asyncId=6のafterイベント関数
  • 異常処理
    Aynch Hookコールバック関数に異常が発生した場合、サービスはエラーログを印刷してすぐに終了します.同時に、すべての「uncaghtException」モニターが削除され、同時に「exit」イベントをトリガします.プロセスをすぐに終了する理由は、これらのAynch Hook関数が不安定であれば、次の同じイベントがトリガされた時にまた異常を投げてしまう可能性があります.これらの関数は主に非同期イベントを傍受するためで、不安定ならば直ちに発見して訂正するべきです.
    ログ印刷
    consolie.logs関数も非同期呼出しであるため、asyncHook関数でconsoline.logsを再起動すると、再度該当のhookイベントをトリガして、デッドサイクル呼出しを引き起こします.だから、async Hook関数で同期印刷ログ方式を使って追跡しなければなりません.fs.writeSync関数を使うことができます.
    async_hooks.createHook({
      init(asyncId, type, triggerAsyncId) {
        const eid = async_hooks.executionAsyncId();
        fs.writeSync(
          1, `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}
    `
    ); } }).enable();
    参考文献
  • async-hook s公式文書
  • Node.js v 8.x新特性Aync Hookプロファイル