具体的なウェブワーカーのユースケース

<ph type="x-smartling-placeholder">

前のモジュールでは、ウェブ ワーカーの概要について説明しました。ウェブワーカーは 入力の応答性を改善するには、JavaScript をメインスレッドから ウェブワーカー スレッドが分離されるため、ウェブサイトのインタラクションが Next Paint(INP)に移動します。 できます。しかし、概要だけでは十分ではありません。このモジュールでは、 ウェブワーカー向けの具体的なユースケースが 提示されています

そのようなユースケースの 1 つとして、ウェブサイトから Exif メタデータを取り除く必要がある これはありえないコンセプトではありません。実際、Flickr などのウェブサイトでは Exif のメタデータを表示する方法を ユーザーに提示して 画像(色深度、カメラのメーカーとモデル、その他の画像など)が 分析できます

ただし、画像を取得して ArrayBuffer に変換するロジックは、 Exif のメタデータの抽出を 完全に行った場合 呼び出すことができます。幸いウェブワーカーのスコープを使用すると 実行することもできます。次に、ウェブワーカーのメッセージング パイプラインを使用して、 EXIF メタデータが HTML 文字列としてメインスレッドに返送され、 表示されます。

ウェブワーカーを使用しない場合のメインスレッド

まず、この作業を行う際にメインスレッドが 使用します。これを行う方法は次のとおりです。

  1. Chrome で新しいタブを開き、DevTools を開きます。
  2. パフォーマンス パネルを開きます。
  3. https://exif-worker.glitch.me/without-worker.html に移動します。
  4. パフォーマンス パネルで、右上にある [録画] をクリックします。 [DevTools] ペインです。
  5. この画像リンク、または Exif を含む別の画像を貼り付けます。 [Get that JPEG!] ボタンをクリックします。
  6. インターフェースに Exif メタデータが表示されたら、もう一度 [Record] をクリックして 録画を停止します。
で確認できます。 <ph type="x-smartling-placeholder">
</ph> 画像メタデータ抽出アプリのアクティビティ全体がメインスレッドで実行されていることを示すパフォーマンス プロファイラ。長いタスクは 2 つあります。1 つはフェッチを実行してリクエストされた画像を取得してデコードするタスクと、もう 1 つは画像からメタデータを抽出するタスクです。 <ph type="x-smartling-placeholder">
</ph> 画像メタデータ抽出アプリのメインスレッド アクティビティ。なお、 アクティビティはメインスレッドで発生します。

ただし、ラスタライザ アプリのすべてがメインスレッドで発生します。メイン 次のことが起こります。

  1. フォームは入力を受け取り、fetch リクエストをディスパッチして最初の Exif メタデータを含む画像の部分です
  2. 画像データは ArrayBuffer に変換されます。
  3. exif-reader スクリプトを使用して、EXIF メタデータを 説明します。
  4. メタデータがスクレイピングされて HTML 文字列が作成され、それが メタデータ閲覧者

次に、同じ動作を実装します。ただし、ウェブ アプリケーション コードを使用して 労働者!

ウェブ ワーカーを含むメインスレッド

ここまで、ブラウザから EXIF のメタデータを抽出する方法を JPEG ファイルがメインスレッドにある場合、 次のワーカーが混在しています

  1. Chrome で別のタブを開き、その DevTools を開きます。
  2. パフォーマンス パネルを開きます。
  3. https://exif-worker.glitch.me/with-worker.html に移動します。
  4. パフォーマンス パネルで、右上にある録画ボタンをクリックします。 [DevTools] ペインの隅にあります。
  5. フィールドにこちらの画像リンクを貼り付けて、[Get that JPEG!] ボタンをクリックします。
  6. インターフェースに Exif メタデータが表示されたら、記録ボタンをクリックします。 録画を停止します。
で確認できます。 <ph type="x-smartling-placeholder">
</ph> メインスレッドとウェブ ワーカー スレッドの両方で発生する画像メタデータ抽出アプリのアクティビティを示すパフォーマンス プロファイラ。メインスレッドにはまだ長いタスクがありますが、大幅に短くなり、画像のフェッチ/デコードとメタデータの抽出は完全にウェブワーカー スレッドで行われます。唯一のメインスレッド処理は、ウェブワーカーとの間でデータの受け渡しを行います。 <ph type="x-smartling-placeholder">
</ph> 画像メタデータ抽出アプリのメインスレッド アクティビティ。なお、 ほとんどの処理はウェブワーカー スレッドで行われます。

これはウェブワーカーの機能です。メインのインフラストラクチャですべて行うのではなく、 メタデータ ビューアに HTML を入力すること以外はすべて、 表示されます。つまり、メインスレッドは他の処理を行うために解放されます。

おそらく最大の利点は このアプリのバージョンとは異なり ウェブワーカーを使用していない場合、exif-reader スクリプトはメインに読み込まれません。 ウェブワーカー スレッドで処理します。つまり exif-reader スクリプトのダウンロード、解析、コンパイルは、 できます。

それでは、これらすべてを可能にするウェブワーカーのコードを詳しく見ていきます。

ウェブワーカーのコードを見る

ウェブワーカーによる違いを確認するだけでは十分ではありません。また、 (少なくともこのケースでは)コードの内容を理解することで、コードの内容を 処理できます

<ph type="x-smartling-placeholder">

ウェブワーカーが処理を完了する前に実行する必要があるメインスレッド コードから始める 画像を入力します。

// scripts.js

// Register the Exif reader web worker:
const exifWorker = new Worker('/js/with-worker/exif-worker.js');

// We have to send image requests through this proxy due to CORS limitations:
const imageFetchPrefix = 'https://res.cloudinary.com/demo/image/fetch/';

// Necessary elements we need to select:
const imageFetchPanel = document.getElementById('image-fetch');
const imageExifDataPanel = document.getElementById('image-exif-data');
const exifDataPanel = document.getElementById('exif-data');
const imageInput = document.getElementById('image-url');

// What to do when the form is submitted.
document.getElementById('image-form').addEventListener('submit', event => {
  // Don't let the form submit by default:
  event.preventDefault();

  // Send the image URL to the web worker on submit:
  exifWorker.postMessage(`${imageFetchPrefix}${imageInput.value}`);
});

// This listens for the Exif metadata to come back from the web worker:
exifWorker.addEventListener('message', ({ data }) => {
  // This populates the Exif metadata viewer:
  exifDataPanel.innerHTML = data.message;
  imageFetchPanel.style.display = 'none';
  imageExifDataPanel.style.display = 'block';
});

このコードはメインスレッドで実行され、画像の URL を送信するフォームを設定します。 使用します。そこから、ウェブワーカーのコードは importScripts で始まります。 外部 exif-reader スクリプトを読み込み、 メインスレッドに追加します。

// exif-worker.js

// Import the exif-reader script:
importScripts('/js/with-worker/exifreader.js');

// Set up a messaging pipeline to send the Exif data to the `window`:
self.addEventListener('message', ({ data }) => {
  getExifDataFromImage(data).then(status => {
    self.postMessage(status);
  });
});
<ph type="x-smartling-placeholder">

この JavaScript により、メッセージ パイプラインがセットアップされ、ユーザーが JPEG ファイルへの URL を含むフォームを送信すると、URL は Web ワーカーに送られます。 次に、JPEG ファイルから EXIF メタデータを抽出します。 は HTML 文字列を作成し、その HTML を window に送り返して、最終的に 次の情報が表示されます。

// Takes a blob to transform the image data into an `ArrayBuffer`:
// NOTE: these promises are simplified for readability, and don't include
// rejections on failures. Check out the complete web worker code:
// https://glitch.com/edit/#!/exif-worker?path=js%2Fwith-worker%2Fexif-worker.js%3A10%3A5
const readBlobAsArrayBuffer = blob => new Promise(resolve => {
  const reader = new FileReader();

  reader.onload = () => {
    resolve(reader.result);
  };

  reader.readAsArrayBuffer(blob);
});

// Takes the Exif metadata and converts it to a markup string to
// display in the Exif metadata viewer in the DOM:
const exifToMarkup = exif => Object.entries(exif).map(([exifNode, exifData]) => {
  return `
    <details>
      <summary>
        <h2>${exifNode}</h2>
      </summary>
      <p>${exifNode === 'base64' ? `<img src="data:image/jpeg;base64,${exifData}">` : typeof exifData.value === 'undefined' ? exifData : exifData.description || exifData.value}</p>
    </details>
  `;
}).join('');

// Fetches a partial image and gets its Exif data
const getExifDataFromImage = imageUrl => new Promise(resolve => {
  fetch(imageUrl, {
    headers: {
      // Use a range request to only download the first 64 KiB of an image.
      // This ensures bandwidth isn't wasted by downloading what may be a huge
      // JPEG file when all that's needed is the metadata.
      'Range': `bytes=0-${2 ** 10 * 64}`
    }
  }).then(response => {
    if (response.ok) {
      return response.clone().blob();
    }
  }).then(responseBlob => {
    readBlobAsArrayBuffer(responseBlob).then(arrayBuffer => {
      const tags = ExifReader.load(arrayBuffer, {
        expanded: true
      });

      resolve({
        status: true,
        message: Object.values(tags).map(tag => exifToMarkup(tag)).join('')
      });
    });
  });
});

少し読みにくいかもしれませんが、これはウェブワーカーにとってかなり複雑なユースケースでもあります。 とはいえ、このユースケースに限定されるものではなく、労力に見合った結果が得られます。 ウェブワーカーは、fetch 呼び出しの分離など、あらゆる種類の処理に使用できます。 レスポンスの処理、ブロックすることなく大量のデータを これはほんの手始めにすぎません。

ウェブ アプリケーションのパフォーマンスを向上させるには ウェブワーカーのコンテキストで合理的に実行できる あらゆるものを指します次のようなメリットがあります。 ウェブサイトの全体的なユーザー エクスペリエンスの向上につながる可能性があります。