Node.jsの重要な概念:クロージャ、タイマー、コールバック、非同期処理、イベント

概要

Node.jsはシングルスレッドかつ非同期な実行環境であり、その特性を理解し、効果的に利用するためには、クロージャ、タイマー制御、イベント駆動、非同期処理、Promise、await/async、コールバック、ウォーターフォールモデルなどの概念を理解する必要があります。

簡単な紹介

0. クロージャ (closure)

クロージャとは、関数が定義されたスコープ(最も近い花括弧内)のデータをプライベート化する仕組みです。通常、花括弧内の変数は互いにアクセスできますが、花括弧外からのアクセスはできません。例えば、ネストされた関数が外側の関数の変数を参照できる一方で、逆は不可能です。

なぜクロージャが必要かというと、Node.jsのシングルスレッド環境では、varで宣言した変数は予め解析されますが、代入は即座に行われません。これにより、代入順序によってundefinedエラーが発生することがあります。また、function宣言は一度に行われるので、内部関数が外部関数の変数を参照できるようにすることでクロージャが形成されます。クロージャは関数のカリー化、デバウンス、スロットリングなどに使用されます。

1. タイマー

setTimeoutの基本的な使用方法を示します。


  setTimeout(() => {
    console.log("setTimeout 5000");
  }, 5000);

  console.log("setTimeout test");
  

上記コードでは、「setTimeout test」がすぐに表示され、5秒後に「setTimeout 5000」が表示されます。

2. コールバック (callback) と非同期 (Async)

Node.jsの非同期プログラミングは主にコールバック関数によって実現されます。コールバック関数はタスクが完了したときに呼び出されます。Node.jsのAPIはすべてコールバックをサポートしています。

例えば、ファイル読み込み中に他の命令を実行し、読み込み完了時にコールバック関数にファイル内容を渡すことで、I/O操作によるブロックを回避できます。

以下は非同期操作の例です:

  • タイマー
  • ネットワーク接続の確立
  • ネットワークストリームデータの読み取り
  • ファイルへの書き込み
  • Ajax送信
  • データベースサービスへのリクエスト

非同期処理をより扱いやすくするために、async/awaitを使用してPromiseオブジェクトを返し、thenメソッドで結果を取得することができます。以下のコードは、この方法を示しています。


  function longOperation(n) {
    return new Promise(resolve => {
      setTimeout(() => resolve(n + 2000), n);
    });
  }

  async function processSteps() {
    console.time("processSteps");
    const time1 = 3000;
    const time2 = await longOperation(time1);
    const time3 = await longOperation(time2);
    const result = await longOperation(time3);
    console.log(`result is ${result}`);
    console.timeEnd("processSteps");
  }

  processSteps();
  

3. イベント (events)

イベントループは、Node.jsの非同期API(タイマー、I/O操作など)を異なるキュー(Timer, Poll, Check)に分けて管理し、同期コードの実行後、イベントループがこれらのキューから非同期APIを処理します。

EventEmitterはイベントモジュールであり、リスナー登録順にイベントが処理されます。emitメソッドはデフォルトで同期的に実行されますが、非同期処理を行う場合はnextTick内で呼ぶことが推奨されます。


  const events = require('events');

  const eventEmitter = new events.EventEmitter();
  eventEmitter.on("start", handleStart);
  eventEmitter.on("data", handleData);

  function handleStart() {
    console.log("start handler");
    eventEmitter.emit("data");
  }

  function handleData() {
    console.log("data 2018");
  }

  eventEmitter.emit("start");
  

タグ: Node.js クロージャ タイマー コールバック 非同期処理

10月4日 08:31 投稿