“readyState” – Alphabetical Advent Calendar 2013
この記事は賞味期限切れです。(更新から1年が経過しています)
“R” は readyState の “R”。
readyState
document.readyState は、HTMLのダウンロード・パース状況を取得できるAPIです。 値は “loading” / “interactive” / “complete” などが返され、 それぞれ以下のような状態を表します。
- loading: ダウンロード中
- interactive: HTMLのダウンロードとパースが完了
- complete: サブリソースのダウンロードが完了
また、readyState の状態が移り変わる毎に、readystatechange イベントが発火されます。
document.addEventListener("readystatechange", function(e){
console.log(document.readyState); // "loading", "interactive", "complete" など
}, false);
DOMContentLoaded
readystatechange と似た働きをもつ物に DOMContentLoaded イベントがありますが、 DOMContentLoaded をサポートしていないブラウザ、例えばIE8以下向けのフォールバックとして readystatechange が使用されたりします。
ごくシンプルに書くと、このような処理をする事になります。
var initialize = function(){
console.log("ready");
// アプリケーションの初期化...
};
var domReadyHandler = function(e){
if(e.type === "DOMContentLoaded"){
document.removeEventListener("DOMContentLoaded", domReadyHandler);
} else {
if(document.readyState !== "complete"){ return; }
document.detachEvent("onreadystatechange", domReadyHandler);
window.detachEvent("onload", domReadyHandler);
}
initialize();
};
if("addEventListener" in document){
document.addEventListener("DOMContentLoaded", domReadyHandler, false);
} else if("attachEvent" in document){
document.attachEvent("onreadystatechange", domReadyHandler);
window.attachEvent("onload", domReadyHandler);
}
DOMContentLoaded の代替として readystatechange の “complete” のタイミングで処理を行います。 環境の判別に “addEventListener” の有無を使用していますが、 これはたまたま DOMContentLoaded のサポート環境と被っていた為です。 (DOMContentLoaded は document.ondomcontentloaded として参照できない為、イベントのサポートの有無で判別しようとすると冗長になってしまいます)
フレーム内コンテンツなどを考慮するとさらに長いコードになりますが、 下記リンクにて詳細に説明されています。
document 以外での readyState
IE10以下に限っては document 以外にも、img要素やscript要素で readyState が使えます。 従来のIEでは script 要素の onload イベントが使用出来なかった為、 スクリプトローダー等ではこれをフォールバックとして使用していたりします。
例えば、複数のスクリプトを動的・同期的に読み込んで実行したいケースでは、 script 要素の async を false にすれば想定する動きをしてくれます。
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously…
var loadSync = function(resources){
resources.forEach(function(name){
var script = document.createElement("script");
script.async = false;
script.src = name;
document.getElementsByTagName("head")[0].appendChild(script);
});
};
loadSync(["jquery.js", "underscore.js", "backbone.js", "main.js"]);
しかし async 属性はIE8以下ではサポートされていない為、 readystatechange イベントでスクリプトのロード状況を監視し、 読み込みが完了した時点でDOMに挿入する事で再現してみます。
// async がサポートしているかを確認
var supportAsync = "async" in document.createElement("script");
var loadSync = function(resources){
var nodes = [];
var count = resources.length;
var head = document.getElementsByTagName("head")[0];
var process = function(){
if(this.readyState === "loaded"){ count--; }
if(! count){
nodes.forEach(function(node){
node.onreadystatechange = null;
head.appendChild(node);
});
}
};
var createNode = function(src){
var node = document.createElement("script");
if(supportAsync){
node.async = false;
node.src = src;
head.appendChild(node);
} else {
node.onreadystatechange = process;
node.src = src;
}
return node;
};
// forEach が polyfill で定義されている前提
resources.forEach(function(name){
nodes.push(createNode(name));
});
};
loadSync(["jquery.js", "underscore.js", "backbone.js", "main.js"]);
IE11からは script要素の readyState は使えなくなり、load イベントの使用が推奨されています。
コメント