【Node.jsストリーム処理の極意】Async/Awaitでイベントベース、Promise、Transform、Duplexを制覇!

2024-07-27

JavaScript、Node.js、Async/Await を用いたストリーム処理の分かりやすい解説

このチュートリアルでは、JavaScript、Node.js、Async/Await を用いたストリーム処理について、分かりやすく解説します。

ストリームとは

ストリームは、データが連続的に流れるパイプのようなものです。データは一度にすべて渡されるのではなく、小さな塊(チャンク)に分割されて渡されます。これは、大きなファイルやネットワークデータなど、処理に時間がかかるデータを読み書きする場合に特に有効です。

Async/Await とは

Async/Await は、非同期処理を扱うための構文です。Promise を用いた従来の非同期処理と比較して、コードをより読みやすく、簡潔に記述することができます。

ES8 の async/await とストリーム

Node.js 10.0.0 以降では、ES8 の async/await を用いてストリームを処理することができます。これは、従来のイベントベースのコードよりも、より簡潔で読みやすいコードを書くことを可能にします。

ストリーム処理の例

以下の例では、fs.createReadStream 関数を使用してファイルを読み込み、その内容をコンソールに出力します。

async function readStream(fileName) {
  const stream = fs.createReadStream(fileName);

  for await (const chunk of stream) {
    console.log(chunk.toString());
  }

  await stream.close();
}

readStream('example.txt');

このコードは、以下のようになります。

  1. fs.createReadStream 関数を使用して、ファイルを読み込むためのストリームを作成します。
  2. for await...of ループを使用して、ストリームからチャンクを順次読み取ります。
  3. 各チャンクをコンソールに出力します。
  4. await stream.close() を使用して、ストリームを閉じます。

パイプライン処理

ストリームは、パイプラインと呼ばれる方法で連結することができます。パイプライン処理を使用すると、複数のストリームを連結し、それぞれからデータを受け取って処理することができます。

以下の例では、fs.createReadStream 関数と fs.createWriteStream 関数を使用して、ファイルを別のファイルにコピーします。

async function copyFile(sourceFileName, destFileName) {
  const readStream = fs.createReadStream(sourceFileName);
  const writeStream = fs.createWriteStream(destFileName);

  await pipeline(readStream, writeStream);
}

copyFile('example.txt', 'copy.txt');
  1. pipeline 関数を使用して、読み取りストリームと書き込みストリームを連結します。
  2. await pipeline を使用して、パイプライン処理が完了するのを待機します。



async function readStream(fileName) {
  const stream = fs.createReadStream(fileName);

  for await (const chunk of stream) {
    console.log(chunk.toString());
  }

  await stream.close();
}

readStream('example.txt');

ファイルを別のファイルにコピーする

async function copyFile(sourceFileName, destFileName) {
  const readStream = fs.createReadStream(sourceFileName);
  const writeStream = fs.createWriteStream(destFileName);

  await pipeline(readStream, writeStream);
}

copyFile('example.txt', 'copy.txt');

ファイルの MD5 ハッシュ値を計算する

async function calculateMD5(fileName) {
  const stream = fs.createReadStream(fileName);
  const hash = crypto.createHash('md5');

  for await (const chunk of stream) {
    hash.update(chunk);
  }

  const digest = hash.digest('hex');
  console.log(digest);
}

calculateMD5('example.txt');

HTTP リクエストから JSON データを読み込み、パースする

async function fetchAndParseJSON(url) {
  const response = await fetch(url);
  const stream = response.body.getReader();

  let json = '';
  for await (const chunk of stream) {
    json += chunk.toString();
  }

  const data = JSON.parse(json);
  console.log(data);
}

fetchAndParseJSON('https://jsonplaceholder.typicode.com/posts/1');
  • 上記のコードは、Node.js 10.0.0 以降で実行する必要があります。
  • fs モジュールは、ファイルシステムへのアクセスを提供します。
  • crypto モジュールは、暗号化機能を提供します。
  • fetch 関数は、HTTP リクエストを実行します。



イベントベースの方法は、ストリーム処理の最も伝統的な方法です。この方法では、ストリームからイベントが発行されるたびに、コールバック関数を呼び出します。

const fs = require('fs');

const stream = fs.createReadStream('example.txt');

stream.on('data', (chunk) => {
  console.log(chunk.toString());
});

stream.on('end', () => {
  console.log('ファイルの読み込みが完了しました。');
});

Promise

Promise を用いた方法は、イベントベースの方法よりも簡潔で、コードを読みやすくすることができます。

const fs = require('fs');

const stream = fs.createReadStream('example.txt');

stream.on('data', (chunk) => {
  console.log(chunk.toString());
});

stream.on('end', () => {
  console.log('ファイルの読み込みが完了しました。');
});

stream.on('error', (err) => {
  console.error(err);
});

Transform streams

Transform streams は、ストリームのデータを変換するために使用することができます。

const fs = require('fs');
const through = require('through2');

const transformStream = through((chunk, encoding, callback) => {
  const upperCaseChunk = chunk.toString().toUpperCase();
  callback(null, upperCaseChunk);
});

const readStream = fs.createReadStream('example.txt');
const writeStream = fs.createWriteStream('copy.txt');

readStream.pipe(transformStream).pipe(writeStream);

Duplex streams

Duplex streams は、読み込みと書き込みの両方が可能なストリームです。

const net = require('net');

const server = net.createServer((socket) => {
  socket.on('data', (data) => {
    socket.write(data.toString().toUpperCase());
  });
});

server.listen(3000);

javascript node.js async-await



Prototype を使用してテキストエリアを自動サイズ変更するサンプルコード

以下のものが必要です。テキストエリアを含む HTML ファイルHTML ファイルに Prototype ライブラリをインクルードします。テキストエリアに id 属性を設定します。以下の JavaScript コードを追加します。このコードは、以下の処理を行います。...


JavaScriptにおける数値検証 - IsNumeric()関数の代替方法

JavaScriptでは、入力された値が数値であるかどうかを検証する際に、isNaN()関数やNumber. isInteger()関数などを利用することが一般的です。しかし、これらの関数では小数点を含む数値を適切に検出できない場合があります。そこで、小数点を含む数値も正しく検証するために、IsNumeric()関数を実装することが有効です。...


jQueryによるHTML文字列のエスケープ: より詳細な解説とコード例

JavaScriptやjQueryでHTMLページに動的にコンテンツを追加する際、HTMLの特殊文字(<, >, &, など)をそのまま使用すると、意図しないHTML要素が生成される可能性があります。これを防ぐために、HTML文字列をエスケープする必要があります。...


JavaScriptフレームワーク:React vs Vue.js

JavaScriptは、Webページに動的な機能を追加するために使用されるプログラミング言語です。一方、jQueryはJavaScriptライブラリであり、JavaScriptでよく行う操作を簡略化するためのツールを提供します。jQueryを学ぶ場所...


JavaScriptにおける未定義オブジェクトプロパティ検出のコード例解説

JavaScriptでは、オブジェクトのプロパティが定義されていない場合、そのプロパティへのアクセスはundefinedを返します。この現象を検出して適切な処理を行うことが重要です。最も単純な方法は、プロパティの値を直接undefinedと比較することです。...



SQL SQL SQL SQL Amazon で見る



JavaScript、HTML、CSSでWebフォントを検出する方法

CSS font-family プロパティを使用するCSS font-family プロパティは、要素に適用されるフォントファミリーを指定するために使用されます。このプロパティを使用して、Webページで使用されているフォントのリストを取得できます。


JavaScript、HTML、およびポップアップを使用したブラウザのポップアップブロック検出方法

window. open 関数は、新しいウィンドウまたはタブを開きます。ブラウザがポップアップをブロックしている場合、この関数はエラーを生成します。このエラーを処理して、ポップアップがブロックされているかどうかを判断できます。window


JavaScriptを使用してHTML要素の背景色をCSSプロパティで設定する方法

このチュートリアルでは、JavaScriptを使用してHTML要素の背景色をCSSプロパティで設定する方法について説明します。方法HTML要素の背景色を設定するには、以下の3つの方法があります。style属性HTML要素のstyle属性を使用して、直接CSSプロパティを指定できます。


JavaScript オブジェクトの長さを取得する代替的な方法

JavaScriptにおけるオブジェクトは、プロパティとメソッドを持つデータ構造です。プロパティはデータの値を保持し、メソッドはオブジェクトに対して実行できる関数です。JavaScriptの標準的なオブジェクトには、一般的に「長さ」という概念はありません。これは、配列のようなインデックスベースのデータ構造ではないためです。


JavaScriptグラフ可視化ライブラリのコード例解説

JavaScriptは、ウェブブラウザ上で動作するプログラミング言語です。その中で、グラフの可視化を行うためのライブラリが数多く存在します。これらのライブラリは、データ構造やアルゴリズムを視覚的に表現することで、理解を深める助けとなります。