2019年4月18日

リソース読み込み: onload と onerror

ブラウザは外部リソース – スクリプト, iframes, 画像 など – の読み込みを追跡することができます。

そのためのイベントが2つあります:

  • onload – ロードが成功した,
  • onerror – エラーが発生した.

スクリプトの読み込み

外部スクリプトにある関数を呼び出す必要があるとしましょう。

次のようにして動的にロードすることができます。:

let script = document.createElement('script');
script.src = "my.js";

document.head.append(script);

…しかし、どうやってそのスクリプトの中で宣言された関数を実行するのでしょう?私たちはそのスクリプトの読み込みまで待つ必要があり、その後に初めて呼び出すことができます。

script.onload

主なヘルパーは load イベントです。スクリプトがロードされ、実行された後にトリガされます。

let script = document.createElement('script');

// 任意のドメインから任意のスクリプトがロードできます
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);

script.onload = function() {
  // スクリプトはヘルパー関数 "_" を作ります
  alert(_); // 関数は利用可能です
};

そのため、onload では、スクリプト変数の利用や関数の実行などが可能です。

…そして、仮に読み込みが失敗したらどうなるでしょう?例えば、そのようなスクリプトがない(404 エラー)もしくはサーバがない、サーバがダウンしている場合です。

script.onerror

スクリプトの読み込み(実行ではない)中に発生したエラーは error イベントで追跡することが可能です。

例えば、存在しないスクリプトを要求してみましょう:

let script = document.createElement('script');
script.src = "https://example.com/404.js"; // こんなスクリプトはありません
document.head.append(script);

script.onerror = function() {
  alert("Error loading " + this.src); // Error loading https://example.com/404.js
};

ここではエラーの詳細を取得することはできないことに注意してください。エラーが 404, 500, または他の何かだったのかは分かりません。単に読み込みに失敗したということだけです。

他のリソース

loaderror イベントは他のリソースに対しても機能します。そこには微妙な違いがあります。

例えば:

<img>, <link> (外部のスタイルシート)
loaderror 両方のイベントは期待通りに機能します。
<iframe>
iframe の読み込みが完了した時の load イベントのみです。ロードが成功した場合とエラーが発生した場合の両方をトリガーします。 これは歴史的な理由によるものです。

サマリ

画像 <img>, 外部スタイル, スクリプトや他のリソースは、それらの読み込みを追跡するために loaderror イベントを提供しています。:

  • load はロードが成功したときにトリガされます。
  • error はロードに失敗したときにトリガされます。

唯一の例外は <iframe> です: 歴史的な理由により、どんな完了にもかかわらず(たとえページが見つからなくても)、常に load をトリガします。

readystatechange イベントもリソースに対して機能しますが、殆ど使われません。なぜなら load/error イベントの方がシンプルなためです。

タスク

重要性: 4

通常、イメージはそれらが作られたときにロードされます。そのため、<img> をページに追加するとき、ユーザにはすぐにはその写真は見えません。まず、ブラウザがそれをロードする必要があります。

すぐにイメージを見るために、次のようにして “事前に” それを作成することができます:

let img = document.createElement('img');
img.src = 'my.jpg';

ブラウザはイメージの読み込みを開始し、キャッシュにそれを覚えます。その後、ドキュメントに同じにイメージが現れるとき(どのような方法でも)、すぐに表示されます。

配列 sources からすべてのイメージをロード、準備ができたら callback を実行する関数 preloadImages(sources, callback) を作成します

例えば、イメージがロードされた後に alert が表示されます。:

function loaded() {
  alert("Images loaded")
}

preloadImages(["1.jpg", "2.jpg", "3.jpg"], loaded);

エラーが発生した場合でも、関数はイメージが “読み込まれた” と想定します。

つまり、callback はすべてのイメージがロードされたかエラーになったかの場合に実行されます。

関数は便利です。例えば、多くのスクロール可能な画像があるギャラリーを表示し、すべての画像がロードされていることを確認したい場合などに使えます。

ソースドキュメントには、テストイメージへのリンクやそれらがロードされたかどうかを確認するコードがあります。それは 300 を出力するはずです。

タスクのためのサンドボックスを開く

アルゴリズム:

  1. 各ソースの img を作ります。
  2. 各イメージの onload/onerror を追加します。
  3. onload または onerror がトリガされた時にカウンタを増やします。
  4. カウンタがソースカウントと等しくなったとき – 完了です: callback()

サンドボックスで解答を開く

チュートリアルマップ

コメント

コメントをする前に読んでください…
  • 自由に記事への追加や質問を投稿をしたり、それらに回答してください。
  • 数語のコードを挿入するには、<code> タグを使ってください。複数行の場合は <pre> を、10行を超える場合にはサンドボックスを使ってください(plnkr, JSBin, codepen…)。
  • 記事の中で理解できないことがあれば、詳しく説明してください。