Document and resource loading¶
Page: DOMContentLoaded, load, beforeunload, unload¶
<https://javascript.info/onload-ondomcontentloaded> のノート。
DOMContentLoadedブラウザーが HTML を完全にロードし、DOM 木が構築されたイベント。しかし画像やスタイルシートのような外部リソースはまだロードされていない可能性がある。DOM の準備ができているので、イベントハンドラーはノードを検索し、インターフェイスを初期化することができる。
loadHTML に加え、画像やスタイルシートのような外部リソースもロードされたイベント。画像のサイズなどがわかる。
beforeunloadユーザーがページから離れているイベント。変更の保存をするか、本当にページから出るかなどを確認したりするのに利用できる。
unloadこれもユーザーがページから離れているイベント。統計情報を取るなどをするタイミングとして利用できる。
DOMContentLoaded¶
イベント DOMContentLoaded は document で起こる。
イベントハンドラーを取り付ける手段が
addEventListener()呼び出ししかない。最初の例では
IMGのサイズを得ようとしているが、リソースはまだロードされていないのでゼロが表示される。
DOMContentLoaded and scripts¶
ブラウザが HTML ドキュメントを処理しているときに SCRIPT タグに遭遇すると、
DOM の構築を続ける前にそれを実行する必要がある。スクリプトが DOM を変更する可能性などがあるためで、DOMContentLoaded はそれを待機しなければならない。つまり、スクリプトの実行が先で、その後に DOMContentLoaded イベントが発生する。
しかし、例外が二つある。次の場合には DOMContentLoaded イベントをブロックしない:
非同期的なスクリプト
document.createElement('script')により生成され、ドキュメントに追加された新しいスクリプト
DOMContentLoaded and styles¶
スタイルシートは DOM に影響を与えないので、イベント DOMContentLoaded はそれらのロードを待機しない。しかし、スタイルシートに依存するスクリプトが存在すると、結果的に待機することになる。
Built-in browser autofill¶
Google Chrome を含む有力なブラウザーは DOMContentLoaded 時にページ内のフォームに自動入力をする。例えば、ページにログインとパスワードのフォームがあり、ブラウザーがその入力値を記憶している場合、DOMContentLoaded ハンドラーは、自動入力を試みる可能性がある。
DOMContentLoaded ハンドラーの反応が遅延するような、先ほどと同様の条件があると、自動入力も待機することになる。
window.onload¶
冒頭のデモコードのイベントハンドラーを、代わりに window.onload に取り付けると、画像のサイズが正しく取得される。
window.onunload¶
window.onunload では遅延を伴わない処理を行うことができる。
navigator.sendBeacon(url, data)なる謎のメソッドを呼び出すのに利用できる。サーバーからの応答を確認することはできない。ページからすでに離れている。
window.onbeforeunload¶
このデモコードが記述されたように働かない?
readyState¶
document.readyState は現在のロード状況を表す。
"loading"ロード中。
"interactive"ページが完全に読み込まれた。
"complete"ページが完全に読み込まれており、かつリソースすべても読み込まれた。
状態が変化したときに起こる readystatechange イベントもある。
document.readyStateはDOMContentLoadedの直前に interactive になる。document.readyStateはすべてのリソースが読み込まれた時点で complete となる。complete に切り替わるというのは
window.onloadと同じ。window.onloadは常に他のすべてのloadハンドラーの後で動作する。
Scripts: async, defer¶
<https://javascript.info/script-async-defer> のノート。
ブラウザーが HTML を読み込んでいるときに SCRIPT タグに出くわすと、DOM の構築を続けることができなくなる。直ちにスクリプトを実行しなければならない。スクリプトを実行して、それからページの残りを処理できるようになる。それゆえ、スクリプト以降の内容へのアクセスに難がある。
ページのいちばん下にスクリプトを配置してしのごうとすると、今度は逆に HTML 全体のロードをスクリプトのそれを待機してからとなり、やはり遅延しがちだ。
defer¶
SCRIPT 要素の defer 属性は、ブラウザーにスクリプトを待たないように指示する。すると、ブラウザーは HTML の処理を続け DOM を構築する。スクリプトをバックグラウンドで読み込み、DOM が完全に構築された時点で実行する。
deferスクリプトはページをブロックしない。deferスクリプトは DOM の準備ができたとき(ただしDOMContentLoadedイベントの前)に実行される。
ブラウザーは通常、ページをスキャンしてスクリプトを探し、それらを並行してダウンロードする。defer スクリプトは定義位置の順序どおりに実行される。
スクリプト間に依存関係がある場合にこの仕様は重要となる。
属性 defer は属性 src がある SCRIPT 要素にしか機能しない。インラインスクリプトの defer は単に無視される。
async¶
属性
asyncはdeferと同様にブラウザーにスクリプトを待たないように指示する。非同期スクリプトは他の非同期スクリプトを待機せず、反対に非同期スクリプトは非同期スクリプトを待機しない。
DOMContentLoadedとasyncスクリプトは互いに待機しない。つまり、どちらが先に起こってもおかしくない。asyncスクリプト同士は、ロードが先に完了したたほうが先に実行されると思っていい。非同期スクリプトは、独立したサードパーティー製スクリプトをページに組み込む場合に最適だ。
属性 async は属性 src がある SCRIPT 要素にしか機能しない。インラインスクリプトの async は単に無視される。
Dynamic scripts¶
script = document.createElement('script') でスクリプトを動的に追加する場合を考える。このようなスクリプトは特に指定がない限り async となる。そうしたくない場合には script.async = false とする。
Resource loading: onload and onerror¶
<https://javascript.info/onload-onerror> のノート。
ブラウザーが外部リソースのロードに成功したかとどうかをチェックすることができるイベントがある。
load: 読み込みに成功したerror: エラーが発生した
Loading a script¶
前章の関数 loadScript() のように、動的にロードしたスクリプトの機能を参照したいとする。
script.onload¶
スクリプトオブジェクトの load イベントは、ロードが成功したら発生する。
script.onerror¶
スクリプトのロード失敗を追跡したければ error イベントが利用できる。
イベント load/error は、ロードそのものしか追跡しない。スクリプトの内容から生じるエラーは、これらのイベントの対象外だ。例えば、スクリプトが正常にロードされれば、たとえその中にプログラミングエラーがあったとしても、load ハンドラーが反応する。window.onerror ハンドラーならばスクリプトのエラーを追跡できる。
Other resources¶
load/error イベントは IMG, IFRAME にも存在するが、ハンドラーが発動する条件が SCRIPT と異なる。
IMGの場合、ノードが DOM に追加されたタイミングではなく、属性srcが設定されてロードが始まったときにloadハンドラーが起動する。IFRAMEの場合、ロードが終了すれば成功でも失敗でもloadハンドラーが起動する。
Crossorigin policy¶
規則として、あるサイトのスクリプトは、他のサイトのコンテンツにアクセスできない。正確に言うと、ある origin (domain, port, protocol) は、他の origin のコンテンツにアクセスできない。たとえ subdomain や別の port があったとしても、これらは互いにアクセスできない、異なる origin とみなされる。
この規則は、他の domain から参照されるリソースにも影響する。他の domain のスクリプトを使用していて、そのスクリプトにエラーがあった場合、エラーの詳細を取得することができない(エラーもコンテンツ扱い)。
こういう規則を CORS と呼ぶ。
同様の CORS は、他の種類のリソースにも適用される。
CORS を許可するには、
SCRIPTタグにcrossorigin属性が必要で、さらにリモートサーバーは特別なヘッダーを提供する必要がある。
CORS アクセスにはレベルが三つある。
crossoriginアクセスは禁止される。
crossorigin="anonymous"サーバーが
Access-Control-Allow-Originヘッダーに*か、こちら側の origin を付けて応答した場合にアクセスが許可される。ブラウザーは認証情報もクッキーもリモートサーバーに送信しない。crossorigin="use-credentials"サーバーが
Access-Control-Allow-Originヘッダーにこちら側の origin とAccess-Control-Allow-Credentials: trueを含めて送り返した場合にアクセスが許可される。ブラウザーは認証情報とクッキーをリモートサーバーに送信する。
スクリプトがあるリモートサーバーが Access-Control-Allow-Origin ヘッダーを用意している場合、それをロードする SCRIPT に crossorigin 属性を持たせればうまくいく(本文のデモではエラー内容を期待どおりに取得できる)。
Tasks¶
Load images with a callback¶
img.srcのセットよりも先にimg.onload,img.onerrorをセットする?イベントハンドラーは共通でいい。したがってカウンターも共通とする。