インターネット
 Computer >> コンピューター >  >> ネットワーキング >> インターネット

Async JavaScriptでインターネット接続状態を正しく判定する方法 ― navigator.onLineの落とし穴とFetch APIによる確実な実装

JavaScriptを使って、アプリがインターネットに接続されているかどうかを確認できるのでしょうか?

本記事では、この「インターネット接続検出」に関する質問に対する最新の答えをご紹介します。解決策には、JavaScriptのFetch APIと、Async/Awaitを使った非同期コードを使用します。その前にまず、広く知られている定番の解決策を見て、それが必ずしも最適な選択肢とは言えない理由を考察してみましょう。

navigatorインターフェースのonlineプロパティであるnavigator.onLineは、ブラウザのオンライン・オフライン状態を検出するためによく使われています。

onlineイベントとofflineイベントのリスナーと組み合わせれば、開発者にとって実装が簡単なシンプルな解決策のように見えます。

navigator.onLineの実装方法

まず、loadイベントリスナーを追加します。loadイベントが発生すると、リスナーはnavigatorインターフェースのonlineプロパティをチェックし、オンライン状態を表示します。

navigatorのonlineプロパティはブール値(trueまたはfalse)を返します。リスナーの処理を完成させるために、三項演算子を使ってステータス表示の値を設定しましょう。

window.addEventListener("load", (event) => {
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = navigator.onLine ? "Online" : "OFFline";
});

ちなみになぜ「navigator」という名前なのでしょうか?これは90年代のブラウザ「Netscape Navigator」へのオマージュです。

HTMLページの中央にid="status"を持つh1要素を配置してください。上記のJavaScriptコードをページに適用すると、「Online」と表示されるはずです。

しかし、これだけではページ読み込み時にしかh1要素が更新されません。onlineイベントとofflineイベントのリスナーを追加して、いずれかのイベントが発生したときに常にステータス表示を更新するようにしましょう。

window.addEventListener("offline", (event) => {
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = "OFFline";
});

window.addEventListener("online", (event) => {
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = "Online";
});

Chrome Dev Toolsの「Application」タブに移動し、「Service Worker」をクリックすると、ブラウザをオフラインとして動作させることができます。

「Offline」チェックボックスを何度かオン・オフしてみてください。発生したofflineイベントとonlineイベントに対して、ステータス表示が即座に反応するのがわかるはずです。

Async JavaScriptでインターネット接続状態を正しく判定する方法 ― navigator.onLineの落とし穴とFetch APIによる確実な実装
Chrome Dev Tools > Applicationタブ > Service Workers > Offlineチェックボックス

もう少し深く掘り下げてみる

一見すると、上記の方法はシンプルで良い解決策に思えます。ところが、navigatorのonlineプロパティやonline/offlineイベントについて詳しく調べていくと、問題があることがわかります。

CanIUse.comでnavigator.onLineを検索すると、このプロパティが提供するonline/offlineステータスは幅広くサポートされていることがわかります。しかし、サポート表の下にある注記を見ると、次のように書かれています。

「Onlineは必ずしもインターネットへの接続を意味するわけではない。単に何らかのネットワークへの接続を意味することもある」

うーん、これは厄介ですね。

つまり、本当にブラウザのオンライン状態を判定したいのであれば、追加の確認手段を開発すべきだということです。

MDNのnavigator.onLineドキュメントも見てみましょう。MDN Web DocsはCanIUse.comの情報を裏付け、さらに注記を加えています。

「ブラウザによってこのプロパティの実装は異なる…trueという値が必ずしもブラウザがインターネットにアクセスできることを意味するとは想定できない。誤検出(false positives)が起こり得る…」

これにより、インターネット接続の検出手段としてnavigatorのonlineプロパティを使うことへの懸念が裏付けられました。外部データソースが利用可能かどうかを把握する必要があるアプリケーションにとって、これは大混乱を招きかねない解決策です。

一例として、プログレッシブウェブアプリ(PWA)がオンラインかどうかを判定しようとする場合が挙げられます。MDNはさらにこう推奨しています。

「…本当にブラウザのオンライン状態を判定したいのであれば、追加の確認手段を開発すべきである」

「navigator online not working」でWeb検索してみると、このプロパティに依存していた開発者が問題に遭遇したさまざまなフォーラム投稿が見つかります。

では、解決策は?

私たちが知る必要があるのは、アプリケーションがルーターやローカルネットワークではなく、本当にインターネットに接続されている瞬間です。JavaScriptファイルに戻って、やり直してみましょう。

考え方はシンプルです。リクエストを送信し、失敗した場合はエラーキャッチで適切に処理します。リクエストが成功すればオンライン、失敗すればオフラインです。

オンライン状態を判定するために、小さな画像を一定間隔でリクエストすることにします。モダンなJavaScriptにはFetch APIと、Async/Awaitを使った非同期コードが用意されています。これらのツールを使って目標を達成しましょう。

checkOnlineStatus()

まず、checkOnlineStatusという名前のasyncアロー関数を作成します。この関数は、navigatorのonlineプロパティと同じようにtrueまたはfalseを返します。

関数内ではtryブロックを設け、1ピクセル画像へのfetchリクエストをawaitします。Service Workerがこの画像をキャッシュしていないことを確認してください。

HTTPレスポンスコードが200から299の間であれば成功を示すので、ステータスコード比較の結果を返します。レスポンスステータスが200〜299ならtrue、それ以外ならfalseになります。

また、リクエストが失敗した場合のエラーをキャッチするcatchブロックも必要です。catchブロックではfalseを返し、この場合は確実にオフラインであることを示します。

const checkOnlineStatus = async () => {
try {
const online = await fetch("/1pixel.png");
return online.status >= 200 && online.status < 300; // true または false
} catch (err) {
return false; // 確実にオフライン
}
};

次に、setIntervalメソッドを使い、匿名のasync関数を渡します。このasync関数はcheckOnlineStatus関数の結果をawaitします。そして、その結果を使って三項演算子で現在のオンライン状態を表示します。

この例をテストするには、インターバルの遅延を3秒(3000ミリ秒)ごとに設定します。ただし、実際にはこれは頻繁すぎます。実際のニーズには30秒ごと(30000ミリ秒)のチェックで十分かもしれません。

setInterval(async () => {
const result = await checkOnlineStatus();
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = result ? "Online" : "OFFline";
}, 3000); // おそらく頻繁すぎるので、30秒ごとなら30000を試そう

新しいコードを保存したら、Chrome Dev ToolsのApplicationタブに戻って、オフライン時の応答をテストしてみましょう。

Async JavaScriptでインターネット接続状態を正しく判定する方法 ― navigator.onLineの落とし穴とFetch APIによる確実な実装
Chrome Dev Tools > Applicationタブ > Service Workers > Offlineチェックボックス

忘れるところでしたが、async機能を持つloadイベントリスナーも含める必要があります!loadイベントでの検出が重要になるのは、おそらくService Workerを利用してオフライン対応を実現しているプログレッシブウェブアプリ(PWA)の場合だけです。それ以外の場合、接続なしではそもそもWebページやアプリが読み込めませんからね。

こちらが新しいloadイベントリスナーです:

window.addEventListener("load", async (event) => {
const statusDisplay = document.getElementById("status");
statusDisplay.textContent = (await checkOnlineStatus())
? "Online"
: "OFFline";
});

最後にひとつ

上記のインターバルコードは、アプリ内で接続状態を表示する用途には適しています。とはいえ、重要なデータリクエストを行う際に、20〜30秒前にチェックされた接続状態に依存することはおすすめしません。

そのため、リクエストの直前にcheckOnlineStatus関数を直接呼び出し、データをリクエストする前にレスポンスを評価すべきです。

const yourDataRequestFunction = async () => {
const online = await checkOnlineStatus();
if (online) {
// データリクエストを実行
}
}

まとめ

navigator.onLineは広くサポートされていますが、アプリケーションが本当にインターネットに接続されているかどうかの判定には信頼性の低い結果をもたらします。Fetch APIと非同期JavaScriptを活用すれば、より信頼性の高いソリューションを素早くコーディングできます。

  1. WordPressでJavaScriptの解析を遅延させる方法|DeferとAsyncの使い方を徹底解説

    表示速度の速いWordPressサイトは、訪問者のユーザー体験の向上、検索エンジンでの視認性の改善、オーガニック流入の増加といった面で大きなメリットをもたらします。 WebページはHTML、CSS、JavaScript、画像で構成されており、ページの読み込み時間を短縮するには、それぞれを最適化する必要があります。特に画像はページサイズに与える影響が大きいため、WordPressの画像最適化プラグインを使ってファイルサイズを削減することが重要です。 コードの種類主な用途HTMLページのコンテンツや構造の定義CSSフォント、色、余白などのスタイリングJavaScriptボタン、フォーム、動画、

  2. Windows 10でネットワーク帯域を消費しているアプリを特定・確認する方法

    インターネットの速度が突然低下した場合、PC上のアプリがバックグラウンドで帯域を消費している可能性があります。Windows 10に標準搭載されている「タスクマネージャー」を使えば、どのアプリがローカルネットワーク経由で通信しているのかを確認でき、帯域がどこへ使われているのかを突き止める手がかりになります。 タスクマネージャーで通信中のアプリを確認する手順 1. タスクマネージャーを起動する キーボードの「Ctrl + Shift + Esc」を同時に押してタスクマネージャーを起動します。簡易表示で開いた場合は、左下にある「詳細情報」ボタンをクリックしてウィンドウを拡張してください。 2.