JavaScriptの非同期処理の基本:PromiseとsetTimeout

現代のWeb開発において、JavaScriptの非同期処理を理解し、適切に扱うことは非常に重要です。ユーザー体験を損なわないスムーズなアプリケーションを構築するためには、バックグラウンドでのデータ取得や時間差での処理実行が不可欠となります。ここでは、非同期処理の核となるPromisesetTimeoutについて、その基本的な仕組みと活用法を深く掘り下げていきます。

これらの機能をマスターすることで、複雑な非同期フローも簡潔かつ堅牢に記述できるようになり、より高度なWebアプリケーション開発への道が開きます。

Promiseの基本と状態

Promiseは、非同期処理が将来的に成功するか失敗するか、その結果を表すためのオブジェクトです。これにより、非同期処理の結果を、まるで同期処理であるかのように扱うことが可能になり、コードの可読性とメンテナンス性が大幅に向上します。

Promiseには、処理の進行状況を示す以下の3つの状態があります。

  • pending (待機中): 非同期処理がまだ完了していない初期状態です。
  • fulfilled (履行済み): 非同期処理が成功し、結果が利用可能になった状態です。
  • rejected (拒否済み): 非同期処理が失敗し、エラーが発生した状態です。

基本的な使い方は、new Promise((resolve, reject) => { ... })のようにコンストラクタでPromiseを作成し、非同期処理が成功したらresolve()を、失敗したらreject()を呼び出します。その後の結果は.then()メソッドで成功時の処理を、.catch()メソッドで失敗時の処理を登録することで受け取れます。Promiseは2015年7月頃から主要なブラウザで広くサポートされており、現在ではJavaScriptの標準的な機能となっています。(出典: 参考情報)

Promiseチェーンと静的メソッド

Promiseの強力な特徴の一つに「チェーン」があります。.then()メソッドは常に新しいPromiseを返すため、複数の非同期処理を連続して実行するように連結することが可能です。これにより、ネストが深くなる「コールバック地獄」を回避し、コードをフラットで読みやすい状態に保つことができます。

さらに、Promiseには複数のPromiseを効率的に扱うための便利な静的メソッドが用意されています。

  • Promise.all(): すべてのPromiseが成功した場合にのみ成功し、いずれか一つでも失敗すると全体が失敗します。
  • Promise.allSettled(): すべてのPromiseが成功か失敗かに関わらず、すべての結果が返された時点で解決します。
  • Promise.race(): 複数のPromiseの中で、最初に解決(成功または失敗)したPromiseの結果を返します。
  • Promise.any(): 複数のPromiseの中で、最初に成功したPromiseの結果を返します。すべて失敗した場合は失敗します。

例えば、複数のAPIエンドポイントから同時にデータを取得し、すべて揃ってから次の処理に進みたい場合はPromise.all()が最適です。これらのメソッドを適切に使い分けることで、複雑な非同期フローを簡潔かつ堅牢に記述できます。最近ではPromise.withResolversのような新しい機能も登場していますが、一部の環境でのサポート状況に注意が必要です。(出典: 参考情報)

setTimeoutの非同期性と活用

setTimeout()は、指定した時間(ミリ秒単位)が経過した後に、一度だけ関数やコードを実行するためのメソッドです。これはJavaScriptにおける最も基本的な非同期処理の一つであり、タイマーが設定されても他の処理の実行をブロックしないという重要な特性を持っています。つまり、プログラムの実行を一時停止させる「一時停止」機能ではないという点に注意が必要です。

使い方は非常にシンプルで、setTimeout(関数, 遅延時間)の形式で使用します。第一引数には実行したい関数を、第二引数にはミリ秒単位の遅延時間を指定します。遅延時間は省略可能で、その場合0ミリ秒となり、現在のイベントループのタスクがすべて完了した後の次のイベントループで実行されます。セキュリティ上のリスクがあるため、第一引数に文字列を渡す方法は推奨されません。

setTimeout()は一意のタイマーIDを返します。このIDをclearTimeout()関数に渡すことで、タイマーの実行をキャンセルすることが可能です。これにより、ユーザーの操作に応じてタイマーを停止したり、不要な処理の実行を防いだりすることができます。指定した遅延時間よりも実際の実行が遅れる場合があるのは、JavaScriptのイベントループの仕組みによるものです。(出典: 参考情報)

URL操作をマスター!location, URLパラメータの取得とエンコード

Webアプリケーションにおいて、URLは単なるアドレス以上の意味を持ちます。現在のページの情報を取得したり、特定のパラメータに基づいてコンテンツを動的に変更したり、あるいはユーザーを別のページにリダイレクトしたりと、URLはユーザー体験の設計に不可欠な要素です。ここでは、JavaScriptでURLを自在に操るためのlocationオブジェクト、URLインターフェース、そしてURLエンコードについて詳しく見ていきます。

これらの知識を身につけることで、より柔軟でインタラクティブなWebサイトを構築できるようになります。

URLの基本構成とlocationオブジェクト

URL(Uniform Resource Locator)は、インターネット上のあらゆるリソースの場所を示す統一されたアドレスです。URLは複数の要素で構成されており、それぞれが特定のリソースに関する情報を提供します。主要な構成要素は以下の通りです。

  • スキーム: リソースにアクセスするためのプロトコル(例: http, https)。
  • ドメイン: Webサイトの識別子(例: example.com)。
  • ポート: サーバーの特定のサービスを指定する番号(例: :8080)。
  • パス: Webサイト内の特定のリソースへのディレクトリパス(例: /products/item123)。
  • クエリパラメータ: サーバーに渡されるキーと値のペア(例: ?category=electronics&sort=price)。
  • フラグメント識別子: ページ内の特定の位置を指定する(例: #section-top)。

JavaScriptでは、グローバルオブジェクトであるlocationを通じて、現在表示されているページのURL情報にアクセスできます。例えば、location.hrefで完全なURL文字列を取得し、location.searchでクエリパラメータ部分(?から始まる文字列)を取得できます。また、location.protocol, location.hostname, location.pathnameなどのプロパティを通じて、個々の構成要素に簡単にアクセスすることが可能です。(出典: 参考情報)

URLインターフェースとパラメータ操作

locationオブジェクトは便利ですが、より高度で構造的なURL操作を行うにはURLインターフェースが強力です。URLコンストラクタを使用すると、URL文字列からURLオブジェクトを作成し、そのオブジェクトのプロパティを通じてURLの各構成要素を詳細に解析したり、変更したりできます。


const urlString = 'https://example.com/search?q=javascript&page=2#results';
const url = new URL(urlString);

console.log(url.protocol); // "https:"
console.log(url.hostname); // "example.com"
console.log(url.pathname); // "/search"
console.log(url.search);   // "?q=javascript&page=2"
console.log(url.hash);     // "#results"

特に便利なのが、クエリパラメータをより簡単に操作するためのURLSearchParamsインターフェースです。url.searchParamsプロパティからアクセスでき、以下のようなメソッドでパラメータを操作できます。

  • append('key', 'value'): パラメータを追加します。
  • get('key'): 指定したキーの最初の値を取得します。
  • set('key', 'value'): 指定したキーの値を設定(上書き)します。
  • delete('key'): 指定したキーのパラメータを削除します。

例えば、既存のURLに新しいクエリパラメータを追加するには、url.searchParams.append('newParam', 'newValue');と記述し、その後url.toString()で完全な新しいURL文字列を取得できます。このURLインターフェースも2015年7月頃から広くサポートされており、現代のWeb開発で頻繁に利用されています。(出典: 参考情報)

URLエンコードとデコード

URLは、スキーム、ドメイン、パスなどを構成する文字として特定の文字セットしか使用できません。例えば、日本語やスペース、一部の記号(&, =, ?など)をURLのパスやクエリパラメータに直接含めると、URLの構造が壊れたり、意図しない挙動を引き起こしたりする可能性があります。このような問題を避けるために、「URLエンコード」が必要になります。

URLエンコードでは、URLに使用できない文字を、パーセント記号(%)とそれに続く16進数のコード(例: スペースは%20、日本語の「あ」は%E3%81%82)に変換します。JavaScriptには、URLエンコードとデコードのための組み込み関数が用意されています。

  • encodeURIComponent(string): URLのコンポーネント(パス、クエリパラメータの値など)をエンコードします。これはURLの予約文字もエンコードするため、クエリパラメータの値部分に最適です。
  • decodeURIComponent(string): encodeURIComponentでエンコードされた文字列をデコードします。

例: encodeURIComponent('商品名 A&B')%E5%95%86%E5%93%81%E5%90%8D%20A%26Bを返します。

類似の関数としてencodeURI()もありますが、こちらはURL全体をエンコードする際に使用され、: / ? & = #などのURLの予約文字はエンコードしません。したがって、個々のクエリパラメータの値やパスの断片をエンコードする場合は、encodeURIComponent()を使用するのが適切です。これらの関数を使いこなすことで、URLを通じて安全かつ正確にデータを送受信できるようになります。

JavaScriptでUUIDを生成し、ローカルストレージを活用しよう

Webアプリケーションを開発する際、一意の識別子を生成したり、ユーザーのデータをブラウザに保存したりするニーズは頻繁に発生します。例えば、一意なセッションIDの生成、オフラインキャッシュの管理、フォーム入力の一時保存などが挙げられます。ここでは、UUID(Universally Unique Identifier)の生成方法と、クライアントサイドでのデータ永続化に便利なローカルストレージの活用法について解説します。

これらの技術を組み合わせることで、よりパーソナライズされた、オフラインでも機能するWebアプリケーションを構築することが可能になります。

UUID生成の基礎と実践

UUID(Universally Unique Identifier)は、世界中で一意であることが保証される128ビットの数値です。衝突する可能性が極めて低いため、データベースの主キー、セッションID、分散システムにおけるエンティティの識別など、多岐にわたる用途で利用されます。UUIDには複数のバージョンがありますが、JavaScriptで一般的に使用されるのはバージョン4(v4)で、これはランダムな数値に基づいて生成されます。

JavaScriptでUUIDを生成する方法はいくつかあります。

  1. Math.random()とビット演算を組み合わせる方法: これはシンプルな実装で、多くのWebサイトで利用されています。乱数を元にUUIDの各セクションを生成します。
  2. 
    function generateUUIDv4() {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
      });
    }
    console.log(generateUUIDv4()); // 例: "f3e1b7c0-5d6a-4e8f-9a1b-2c3d4e5f6a7b"
        
  3. Web Crypto APIのcrypto.randomUUID(): これはより安全で、モダンなブラウザで利用可能な方法です。暗号学的に強力な乱数生成器を使用します。
  4. 
    if (crypto && crypto.randomUUID) {
      console.log(crypto.randomUUID()); // 例: "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d"
    } else {
      // フォールバックとして上記の方法を使用
    }
        

crypto.randomUUID()はより推奨される方法であり、ほとんどの現代のブラウザでサポートされています。これらの方法で生成されたUUIDは、アプリケーション内でオブジェクトを一意に識別するために活用できます。

ローカルストレージの活用法

ローカルストレージ(localStorage)は、Webブラウザが提供するクライアントサイドのデータ永続化メカニズムです。これにより、Webサイトはユーザーのブラウザにキーと値のペアを保存し、そのデータはブラウザを閉じたり、コンピュータを再起動したりしても消えることなく保持されます。これは、セッションストレージ(sessionStorage)がブラウザタブを閉じるたびにデータが消えるのとは対照的です。

ローカルストレージの基本的なAPIは非常にシンプルで直感的です。

  • localStorage.setItem(key, value): 指定したキーでデータを保存します。値は常に文字列として保存されるため、オブジェクトや配列を保存する場合はJSON.stringify()で文字列に変換する必要があります。
  • localStorage.getItem(key): 指定したキーのデータを取得します。取得したデータがJSON文字列の場合は、JSON.parse()で元のオブジェクトに戻す必要があります。
  • localStorage.removeItem(key): 指定したキーのデータを削除します。
  • localStorage.clear(): ローカルストレージ内のすべてのデータを削除します。

例として、ユーザーの設定情報を保存する場合を考えてみましょう。


const userSettings = {
  theme: 'dark',
  notifications: true
};

// オブジェクトをJSON文字列に変換して保存
localStorage.setItem('userSettings', JSON.stringify(userSettings));

// データを取得し、JSON文字列をオブジェクトに戻す
const storedSettings = JSON.parse(localStorage.getItem('userSettings'));
console.log(storedSettings.theme); // "dark"

ローカルストレージは、ユーザーのブラウザセッションをまたいでデータを保持する必要がある場合に非常に強力なツールとなります。

データ永続化のメリットと注意点

ローカルストレージを利用してデータを永続化することには、多くのメリットがあります。

  • ユーザーエクスペリエンスの向上: ユーザーの設定(テーマ、言語、ログイン状態など)を保存し、次回の訪問時にも同じ設定を適用することで、パーソナライズされた体験を提供できます。
  • オフライン対応: アプリケーションがオフラインになった際でも、以前にキャッシュされたデータを利用して一部の機能を提供できます。
  • パフォーマンス改善: 頻繁に利用するデータをローカルに保存することで、サーバーへのリクエストを減らし、ページのロード時間を短縮できます。
  • フォームデータの一時保存: ユーザーが入力途中のフォームデータを一時的に保存し、誤ってページを閉じた場合でも入力を復元できます。

しかし、ローカルストレージにはいくつかの注意点も存在します。

  • 容量制限: 一般的に5MB程度の容量制限があります。大量のデータを保存するには向きません。
  • セキュリティ: クロスサイトスクリプティング(XSS)攻撃に対して脆弱であり、機密情報(パスワードなど)の保存には絶対に使用しないでください。ローカルストレージはHTTPリクエストと共に送信されないため、Cookieよりも安全な側面もありますが、悪意のあるJavaScriptコードからはアクセス可能です。
  • 同期的なアクセス: ローカルストレージへのアクセスは同期的に行われるため、大量のデータを読み書きするとUIスレッドをブロックし、アプリケーションの応答性を低下させる可能性があります。
  • 文字列のみ: 値は必ず文字列として保存されます。複雑なデータ構造はJSON.stringify()JSON.parse()で変換する必要があります。

これらのメリットと注意点を理解し、適切な場面でローカルストレージを活用することが、堅牢でユーザーフレンドリーなWebアプリケーション開発への鍵となります。機密性の高いデータや大量のデータを扱う場合は、IndexedDBなどの別の永続化メカニズムを検討するべきでしょう。

タイマー機能とデバッグに役立つconsole.log

JavaScriptで時間に基づいた処理を実行したり、コードの実行フローや変数の状態を把握したりすることは、Webアプリケーション開発において日常的に行われるタスクです。アニメーションの制御、一定間隔でのデータ更新、そして何よりも問題が発生した際の原因究明には、適切なツールと理解が不可欠です。ここでは、setIntervalによる繰り返し処理の制御、強力なconsole.logファミリーを使ったデバッグ術、そしてコードのパフォーマンスを測定するタイミングAPIについて深掘りします。

これらの技術を使いこなすことで、より動的で安定したアプリケーションを開発し、効率的なデバッグプロセスを実現できるようになります。

setIntervalで繰り返し処理を制御

setInterval()は、指定した時間(ミリ秒単位)ごとに繰り返し関数またはコードを実行するためのメソッドです。setTimeout()が一度だけ実行されるのに対し、setInterval()は明示的に停止されるまで処理を繰り返します。これは、一定間隔でサーバーから新しいデータを取得したり、時計のようなリアルタイム表示を更新したりする場合に非常に便利です。

使い方はsetInterval(関数, 遅延時間)の形式で、setTimeout()と同様です。第一引数に実行したい関数を、第二引数にミリ秒単位の遅延時間を指定します。


let counter = 0;
const intervalId = setInterval(() => {
  console.log('カウント:', counter++);
  if (counter >= 5) {
    clearInterval(intervalId); // 5回実行したら停止
  }
}, 1000); // 1秒ごとに実行

setInterval()setTimeout()と同様に一意のタイマーIDを返し、このIDをclearInterval()関数に渡すことで、繰り返し処理を停止できます。この停止処理を忘れると、ページが閉じられるまで不要な処理がバックグラウンドで動き続けるため、メモリリークやパフォーマンス低下の原因となる可能性があります。

注意点として、setInterval()で指定した遅延時間は、あくまで次の処理を実行するまでの「最短時間」であり、実際の実行は指定した時間より遅れる場合があります。これは、JavaScriptがシングルスレッドであり、前の処理が実行中であったり、イベントキューに他のタスクが溜まっていたりする場合に発生します。ブラウザの描画タイミングに合わせたアニメーションなどには、より最適化されたrequestAnimationFrame()の利用が推奨されます。

デバッグに必須!console.logの活用術

Web開発において、デバッグは避けて通れないプロセスです。その中でも最も基本的なツールがconsole.log()ですが、log以外にもconsoleオブジェクトにはデバッグ作業を格段に効率化する強力なメソッドが多数用意されています。

  • console.log(message, optionalParams): 最も一般的なログ出力。変数、オブジェクト、文字列などをコンソールに表示します。
  • console.warn(message, optionalParams): 警告メッセージを出力します。多くの場合、黄色い背景で表示され、注意を促します。
  • console.error(message, optionalParams): エラーメッセージを出力します。赤い背景で表示され、通常はスタックトレースも表示されるため、エラーの発生源を特定するのに役立ちます。
  • console.info(message, optionalParams): 情報メッセージを出力します。logと似ていますが、情報として区別できます。
  • console.debug(message, optionalParams): デバッグメッセージを出力します。通常はinfoと似ていますが、デバッグモードでのみ表示されるように設定できる場合があります。
  • console.table(data): 配列やオブジェクトのデータをテーブル形式で整形して表示します。特に複雑なデータ構造を視覚的に把握する際に非常に便利です。
  • console.group(label) / console.groupEnd(): 関連する複数のログメッセージをグループ化して表示します。階層的に整理できるため、大量のログの中から特定の情報を見つけやすくなります。

これらのconsoleメソッドを適切に使い分けることで、アプリケーションの実行状況をより詳細に、かつ視覚的に分かりやすく把握できます。単に変数の中身を見るだけでなく、処理のどの段階で何が起きているのかを効率的に追跡し、問題の原因を素早く特定できるようになります。

パフォーマンス計測とタイミングAPI

Webアプリケーションのパフォーマンスは、ユーザーエクスペリエンスに直結する重要な要素です。特に非同期処理が多いアプリケーションでは、どの処理に時間がかかっているのかを把握し、最適化することが不可欠です。JavaScriptには、コードの実行時間を計測するための機能がいくつか用意されています。

最も手軽な方法は、consoleオブジェクトのタイミングメソッドを使用することです。

  • console.time(label): タイマーを開始します。labelはタイマーの識別子です。
  • console.timeEnd(label): タイマーを終了し、console.time()が開始されてからの経過時間をコンソールに出力します。

console.time('heavyCalculation');
// 時間がかかる可能性のある処理
for (let i = 0; i < 1000000; i++) {
  // 何らかの計算
}
console.timeEnd('heavyCalculation'); // 例: heavyCalculation: 15.234ms

より詳細なパフォーマンス計測が必要な場合は、Performance APIを利用できます。performance.now()は、現在の時刻をミリ秒単位の高精度なタイムスタンプで返します。これにより、特定のコードブロックの実行時間をより正確に計測できます。


const startTime = performance.now();
// 時間がかかる処理
doSomething();
const endTime = performance.now();
console.log(`処理にかかった時間: ${endTime - startTime}ms`);

また、PerformanceObserverなどの高度なAPIを使用することで、リソースのロード時間、描画パフォーマンス、ユーザーのインタラクションタイミングなど、より包括的なパフォーマンスデータを収集・分析することも可能です。これらのタイミングAPIを活用することで、パフォーマンスボトルネックを特定し、Webアプリケーションの速度と応答性を向上させるための具体的な改善策を見つけることができます。

JavaScriptを使いこなすための応用テクニック

これまでのセクションでは、JavaScriptの非同期処理の基本からURL操作、データ永続化、デバッグ手法までを解説してきました。しかし、JavaScriptの奥深さはこれに留まりません。より複雑な非同期処理を扱うためのシンタックスシュガー、JavaScriptがコードを実行する仕組み、そして重い処理をUIスレッドから分離する方法など、さらに高度なテクニックを学ぶことで、あなたの開発スキルは次のレベルへと引き上げられます。

ここでは、async/awaitイベントループ、そしてWeb Workersといった応用的な概念と技術について解説し、JavaScriptをさらに深く理解し使いこなすための知識を提供します。

async/awaitで非同期処理をより簡潔に

async/awaitは、Promiseを基盤とした非同期処理をより簡潔かつ読みやすく記述するためのシンタックスシュガーです。複雑なPromiseチェーンをtry...catch構文と組み合わせることで、まるで同期処理を記述しているかのような感覚で非同期コードを扱えるようになります。これにより、非同期処理特有の複雑さが軽減され、コードの可読性と保守性が大幅に向上します。

  • asyncキーワード: 関数宣言の前にasyncを付けることで、その関数が非同期関数であることを示します。async関数は常にPromiseを返します。
  • awaitキーワード: awaitはasync関数の中でしか使用できません。Promiseの解決(成功または失敗)を待機し、Promiseが解決されるまで関数の実行を一時停止します。解決されると、そのPromiseの解決値が返されます。

async function fetchData() {
  try {
    console.log('データ取得開始');
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
      throw new Error(`HTTPエラー: ${response.status}`);
    }
    const data = await response.json();
    console.log('データ取得成功:', data);
    return data;
  } catch (error) {
    console.error('データ取得失敗:', error);
    throw error; // エラーを再スロー
  }
}

fetchData();

この例では、fetchのPromiseが解決されるまでawaitresponseの代入を待ち、次にresponse.json()のPromiseが解決されるまでawaitdataの代入を待ちます。エラーが発生した場合は、同期処理と同じようにtry...catchで捕捉できるため、エラーハンドリングも直感的です。async/awaitは現代のJavaScript開発においてデファクトスタンダードとなっており、Promiseを直接扱うよりも推奨される記述方法です。

JavaScriptのイベントループを理解する

JavaScriptは基本的にシングルスレッドで動作します。これは一度に一つの処理しか実行できないことを意味しますが、Webアプリケーションがフリーズすることなく非同期処理を滑らかに実行できるのは、イベントループ(Event Loop)という仕組みのおかげです。イベントループは、JavaScriptの実行環境(ブラウザやNode.js)の根幹をなす要素であり、非同期処理のスケジューリングと実行を管理します。

イベントループの主な構成要素は以下の通りです。

  • コールスタック (Call Stack): 実行中の関数が積まれる領域です。同期的なコードがここに積まれ、実行が完了すると取り除かれます。
  • ヒープ (Heap): オブジェクトや変数が格納されるメモリ領域です。
  • イベントキュー (Event Queue / Callback Queue): setTimeoutやDOMイベントなどの非同期処理が完了した際に実行されるコールバック関数が積まれる領域です。
  • マイクロタスクキュー (Microtask Queue): Promise.then()async/awaitで解決されるコールバック関数が積まれる領域です。イベントキューよりも優先して実行されます。

イベントループは、コールスタックが空になると、まずマイクロタスクキューにタスクがあればそれをすべて実行し、その後イベントキューから最も古いタスクを取り出してコールスタックにプッシュします。この仕組みがあるため、たとえsetTimeout(callback, 0)と指定しても、コールスタック上の同期処理がすべて完了し、かつマイクロタスクキューが空になった後に初めてcallbackが実行されるのです。イベントループを理解することは、非同期処理の実行順序を正確に予測し、デッドロックやパフォーマンスの問題を回避するために不可欠です。

Web Workersで並列処理を実現

JavaScriptがシングルスレッドであるため、計算量の多い処理をメインスレッドで実行すると、ブラウザのUIがフリーズし、ユーザーエクスペリエンスが著しく低下する可能性があります。Web Workersは、この問題を解決するために導入された技術で、JavaScriptコードをバックグラウンドで実行し、メインのUIスレッドをブロックすることなく重い処理を実行できるようにします。これにより、JavaScriptが擬似的に並列処理を実現できるようになります。

Web Workersは、専用のスクリプトファイル内で実行され、メインスレッドとは完全に独立しています。メインスレッドとWorkerスレッド間の通信は、メッセージパッシングを通じて行われます。


// main.js
const worker = new Worker('worker.js'); // Workerを生成

worker.postMessage({ number: 1000000 }); // Workerにメッセージを送信

worker.onmessage = function(e) {
  console.log('メインスレッドで結果を受信:', e.data.result);
};

// worker.js
onmessage = function(e) {
  const number = e.data.number;
  let sum = 0;
  for (let i = 0; i < number; i++) {
    sum += i;
  }
  postMessage({ result: sum }); // メインスレッドに結果を送信
};

Web Workersが適しているのは、複雑な数値計算、大量のデータ処理、画像処理、ファイルの圧縮・解凍など、CPUリソースを多く消費するタスクです。ただし、Web WorkersはDOMに直接アクセスできないため、UIの操作はメインスレッドで行う必要があります。また、Workerとの通信にはメッセージングのオーバーヘッドが発生するため、非常に小さなタスクには不向きです。

Web Workersには、他にも複数のWorkerが同じインスタンスを共有できるShared Workersや、ネットワークリクエストのプロキシとして機能するService Workersなど、用途に応じたバリエーションがあります。これらを活用することで、高性能で応答性の高いWebアプリケーションを構築することが可能になります。