序文
誰もがJavaScriptスクリプトの読み込みに関する多くの問題に遭遇したと思います。主にいくつかの点で -
1>同期スクリプトと非同期スクリプトによって引き起こされるファイルの読み込み、ファイルの依存関係、実行順序に関する問題
2>同期スクリプトと非同期スクリプトによって引き起こされるパフォーマンス最適化の問題
スクリプト読み込みのすべての側面を深く理解することは、実際的な問題を解決するのに役立つだけでなく、パフォーマンスの最適化を把握して実行することを助長します。
最初にスクリプトタグコードを見てください -
コードコピーは次のとおりです。
<スクリプトsrc = "js/myapp.js"> </script>
<head>に配置すると、すべてのページレンダリング作業をブロックし、ユーザーはスクリプトがロードされて実行されるまで「死の白いスクリーン」状態にとどまります。 <body>の最後にあるスクリプトは、ユーザーが活力のない静的ページを見るだけです。クライアントレンダリングが効果のないコントロールと空のボックスで散らばることになっている場合。テストケースを取ります -
コードコピーは次のとおりです。
<!doctype html>
<html>
<head lang = "en">
<メタcharset = "utf-8">
<title> asyncロードスクリプト</title>
<スクリプトsrc = "js/test.js"> </script>
</head>
<body>
<div>私はコンテンツです</div>
<img src = "img/test.jpg">
</body>
</html>
その中で、test.jsのコンテンツ -
コードコピーは次のとおりです。
alert( '私は頭の中のスクリプトコードです。ここでJSを実行した後、ボディコンテンツレンダリングが始まります!');
アラートは一時停止ポイントであることがわかり、この時点でページは空白です。ただし、この時点でページ全体がロードされていることに注意してください。ボディに特定のSRC属性(上記のIMGタグなど)のタグが含まれている場合、ブラウザは現時点で関連するコンテンツのロードを開始しています。要するに、JSエンジンとレンダリングエンジンの作業タイミングは相互に排他的であることに注意する必要があります(一部の本はそれをUIスレッドと呼んでいます)。
したがって、ページの見た目を改善する責任のあるスクリプトが必要であり、すぐに使用する必要があり、後でロードできるスクリプトは後で読み込まれます。
1。スクリプト実行遅延
今では、ページ<body>タグの最後にスクリプトを配置することがますます一般的になりつつあります。このようにして、一方では、ユーザーはページをより速く見ることができ、一方で、スクリプトはロードされたDOM要素を直接操作できます。この「移動」は、ほとんどのスクリプトにとって大きな改善です。ページモデルは次のとおりです -
コードコピーは次のとおりです。
<!doctype html>
<html>
<head lang = "en">
<! - メタデータとスクリプトシートはこちら - >
<スクリプトsrc = "headscript.js"> </script>
</head>
<body>
<! - コンテンツはここに行きます - >
<スクリプトsrc = "bodyscript.js"> </script>
</body>
</html>
これにより、ページのレンダリング時間が大幅に高速化されますが、これにより、ユーザーがBodyScriptがロードされる前にページと対話する機会を提供する可能性があることに注意してください。完全なドキュメントをロードする前にブラウザがスクリプトをロードできない理由は、遅い接続を介して送信される大きなドキュメント用の大きなボトルネックです。
理想的には、スクリプトの読み込みは、ドキュメントの読み込みと同時に行う必要があり、DOMのレンダリングに影響しません。このようにして、ドキュメントの準備ができたら、対応するスクリプトが<script>タグの順序でロードされているため、スクリプトを実行できます。
Defer、つまり、この要件を達成することができます。
コードコピーは次のとおりです。
<script src = "deferredscript.js"> </script>
Defer属性を追加することは、ブラウザを通知するのと同等です。このスクリプトのロードをすぐに開始してください。ただし、ドキュメントの準備が整い、Defer属性のあるすべてのスクリプトが実行される前に実行が終了するまで待ってください。
このようにして、ヘッドタグに遅延スクリプトを入力すると、スクリプトをボディタグに配置することのすべての利点が得られ、大きなドキュメントの読み込み速度を大幅に改善できます。この時点のページモードは -
コードコピーは次のとおりです。
<!doctype html>
<html>
<head lang = "en">
<! - メタデータとスクリプトシートはこちら - >
<スクリプトsrc = "headscript.js"> </script>
<script src = "deferredscript.js" defer> </script>
</head>
<body>
<! - コンテンツはここに行きます - >
</body>
</html>
ただし、すべてのブラウザがDeferをサポートするわけではありません(一部の最新のブラウザの場合、Deferが宣言された場合、内部スクリプトはdocument.writeおよびdomレンダリング操作を実行しません。両方ともIE4+サポートDefer属性)。つまり、ドキュメントのロード後に遅延スクリプトを実行できるようにする場合、jQueryの$(document).readyなどの構造のすべての遅延スクリプトのコードをカプセル化する必要があります。訪問者のほぼ97%が並行ロードの利点を享受できるのに対し、訪問者の3%がまだフル機能のJavaScriptを使用できるため、これは価値があります。
2。スクリプトの完全な並列化
スクリプトをロードして、1つのステップをより速く実行します。延期スクリプトが次々と実行されるまで待ちたくありません(Deferは、ドキュメントがドキュメントのロードを静かに待っている順序付けられたキューイングシナリオを思い出させます)。これらのスクリプトを実行する前にドキュメントの準備が整うまで待ちたくありません。これらのスクリプトをできるだけ早くロードして実行したいと思います。ここでは、HTML5の非同期属性を考えますが、それが混oticとした無秩序であることに注意してください。
たとえば、2つの完全に無関係なサードパーティスクリプトをロードし、ページがそれらなしでうまく実行され、誰が最初に実行し、後で実行するのか気にしないでください。したがって、これらのサードパーティスクリプトでASYNC属性を使用することは、ペニーを使わずにランニング速度を改善することと同等です。
ASYNC属性は、HTML5に新たに追加されます。この関数は延期に似ています。つまり、スクリプトのダウンロード中にドムレンダリングを可能にします。ただし、ダウンロード後にできるだけ早く実行されます(つまり、JSエンジンはすぐにアイドル状態で実行されます)。スクリプトが順番に実行されるという保証はありません。オンロードイベントの前に完了します。
Firefox 3.6、Opera 10.5、IE 9、および最新のChromeとSafariはすべてAsync属性をサポートしています。 AsyncとDeferは同時に使用できるため、IE 4後のすべてのIEは非同期負荷をサポートしますが、AsyncがDeferを上書きすることに注意してください。
その後、この時点でのページモデルは次のとおりです -
コードコピーは次のとおりです。
<!doctype html>
<html>
<head lang = "en">
<! - メタデータとスクリプトシートはこちら - >
<スクリプトsrc = "headscript.js"> </script>
<script src = "deferredscript.js" defer> </script>
</head>
<body>
<! - コンテンツはここに行きます - >
<script src = "asyncscript1.js" async defer> </scrip>
<script src = "asyncscript2.js" async defer> </scrip>
</body>
</html>
ここで実行命令に注意してください - 各スクリプトファイルがロードされ、headscript.jsが実行され、DefferedScript.jsがドムレンダリング中にバックグラウンドにロードされます。次に、defferedscript.jsと2つの非同期スクリプトがDOMレンダリングの最後に実行されます。 Async属性をサポートするブラウザの場合、これらの2つのスクリプトは順序付けられないことに注意してください。
3。プログラム可能なスクリプトの読み込み
上記の2つのスクリプトプロパティの関数は非常に魅力的ですが、互換性の問題により広く使用されていません。したがって、スクリプトを使用して、他のスクリプトをさらにロードします。たとえば、特定の条件を満たしているユーザーにのみスクリプトを読み込みたいと考えています。
ブラウザAPIレベルでは、サーバースクリプトをクロールして実行する2つの合理的な方法があります -
1> ajax要求を生成し、評価関数を使用して応答を処理します
2> <script>タグをDOMに挿入します
ブラウザは私たちのHTTP要求を生成することを心配するため、後者の方法が優れています。さらに、評価にはいくつかの実際的な問題があります。範囲の漏れ、デバッグは乱雑であり、パフォーマンスも低下する可能性があります。したがって、feature.jsという名前のスクリプトをロードする場合は、次のようなコードを使用する必要があります。
コードコピーは次のとおりです。
var head = document.getElementsByTagname( 'head')[0];
var script = document.createelement( 'script');
script.src = 'feature.js';
head.AppendChild(スクリプト);
もちろん、コールバックリスニングに対処する必要があり、HTML5仕様はコールバックをバインドできるOnloadプロパティを定義します。
コードコピーは次のとおりです。
script.onload = function(){
console.log( 'スクリプトロード...');
}
ただし、IE8および古いバージョンはオンロードをサポートしておらず、onreadedStateChangeをサポートしています。さらに、エラーに対処する奇妙なことはまだたくさんあります。ここでは、labjs、yepnope、requirejsなど、人気のある学校ベースの荷重ライブラリを参照できます。
次のように、私は自分で単純なLoadJSファイルをカプセル化します -
コードコピーは次のとおりです。
var loadjs = function(url、callback){
var head = document.getElementsByTagname( 'head')[0];
var script = document.createelement( 'script');
script.src = url;
script.type = "text/javascript";
head.AppendChild(スクリプト);
//スクリプトタグ、IEの下にcondreadystatechangeイベントがあり、W3C標準の下にオンロードイベントがあります
// IE9+は、W3C標準のオンロードもサポートしています
var ua = navigator.useragent、
ua_version;
// IE6/7/8
if(/msie([^;]+)/。test(ua)){
ua_version = parsefloat(regexp ["$ 1"]、10);
if(ua_version <= 8){
script.onreadystatechange = function(){
if(this.readystate == "loaded"){
折り返し電話();
}
}
} それ以外 {
script.onload = function(){
折り返し電話();
};
}
} それ以外 {
script.onload = function(){
折り返し電話();
};
}
};
document.writeのスクリプトの非同期ロードについては話しません。ブラウザの違いが本当に圧倒的であるため、これを行う人はほとんどいません。
画像オブジェクトを使用してJSファイルを非同期にプリロードすると、内部のJSコードは実行されないことに注意してください。
最後に、requirejsの非同期ロードスクリプトについて話しましょう。
requirejsは、ターゲットスクリプトが順番に実行されることを保証するものではなく、実行順序がそれぞれの依存関係要件を満たすことができることのみを保証します。したがって、すべてのスクリプトができるだけ早く並行してロードされ、依存関係トポロジに従って整然と実行されるようにします。
4。概要
OK、これに関しては、非同期ロードスクリプトのステートメントが終了しました。ここでもう一度最適化の順序について話させてください -
1>従来の方法では、スクリプトタグを使用してHTMLドキュメントに直接埋め込みます。ここに2つの状況があります -
a>ヘッドタグに埋め込まれている - そうすることで、ドキュメントコンテンツ内の他の静的リソースファイルの並列負荷に影響しないことに注意してください。ドキュメントコンテンツのレンダリングに影響します。つまり、この時点でのレンダリングがブロックされ、白い画面が表示されます。
B>ボディタグの下部に埋め込まれました - 白いスクリーンの現象を避けるために、DOMをレンダリングしてスクリプトを実行することを優先しますが、問題は再び発生します。最初に最初の質問について説明しましょう - DOMドキュメントのコンテンツが比較的大きい場合、相互作用イベントのバインディングが遅れ、エクスペリエンスが少し悪くなります。もちろん、ニーズに基づいて最初に重要なスクリプトを実行する必要があります。 2番目の問題について話しましょう。スクリプトファイルは本体の底までにあるため、これらのスクリプトの読み込みはヘッドのスクリプトと比較して遅れます。したがって、体の底に関しては、最適化の終点ではありません。
c> Defer属性を追加 - スクリプトができるだけ早く並行してロードされることを願っていますが、このスクリプトのバッチを頭に入れます。スクリプトの読み込みは、ドキュメントの読み込みと同時に実行する必要があり、DOMのレンダリングに影響しません。これにより、ドキュメントの準備ができたらスクリプトを実行できます。したがって、延期属性があります。しかし、その互換性に注意してください。 Defer属性をサポートしていないブラウザの場合、jqueryなどの$(document)のコードをカプセル化する必要があります。 Defer属性を持つすべてのスクリプトは、外観の順序に従って順番に実行されるため、厳密に同期されていることに注意する必要があります。
2>前のポイントは、同期実行スクリプトに関するものです(これらのスクリプトの読み込みプロセスは並行しているが、最初にリクエストをトリガーする人とリクエストをトリガーする人の違いに注意してください)。次の最適化ポイントは、「並列実行スクリプト」です。もちろん、ある時点では、1つのJSファイルのみが実行されることを知っています。ここでの「並列」は、JSエンジンがこの時点でアイドル状態である限り、最初にロードする人が誰でも、すぐに実行されることを意味します。ここでの最適化は2つのタイプに分かれています -
A>非同期プロパティの追加 - 上記の最適化ポイントを実際に完了することができますが、高制限があります。つまり、非依存スクリプトの読み込みのみです。最も適切な例は、複数のサードパーティスクリプトを紹介することです。また、Deffer属性との組み合わせは本当に大したことです。もちろん、互換性の問題もあります。上記の3つの問題は、まれなアプリケーションにつながりました。 ASYNCを使用する場合、依存関係の問題に細心の注意を払う必要があります。
b>スクリプトロードスクリプト - 明らかに、これを使用して「スクリプトの並列実行」の目的を実現します。同時に、スクリプト依存関係の制御も促進するため、必要な荷重にインテリジェントな負荷管理を使用します。
わかりました、それだけです。
ここでは、非同期ロードスクリプトに関連するコンテンツについて話しているだけです。コンテンツには別の部分があります。これは、スタイルファイルまたはその他の静的リソースの非同期ロードです。つづく......