AJAX の登場により、Web アプリケーション クライアントの動作モードが大きく変わり、ユーザーは煩わしいページの頻繁な更新に耐えることなく作業に集中できるようになりました。理論上、AJAX テクノロジーはユーザー操作の待ち時間を大幅に短縮し、ネットワーク上のデータ トラフィックを節約できます。ただし、常にそうとは限りません。 AJAX を使用したシステムの応答速度が低下するというユーザーからの苦情がよくあります。
著者は長年 AJAX の研究開発に従事しており、中国で比較的成熟した AJAX プラットフォームである Dorado の開発に参加しました。著者の経験によれば、この結果の根本原因は AJAX ではありません。多くの場合、システムの応答速度の低下は、不合理なインターフェイス設計や効率の悪いプログラミング習慣によって引き起こされます。以下では、AJAX 開発プロセス中に注意を払う必要があるいくつかの側面を分析します。
クライアントプログラミングとリモートプロシージャコールの適切な使用。
クライアント側のプログラミングは主に JavaScript に基づいています。 JavaScript はインタプリタ型プログラミング言語であり、Java に比べて動作効率が若干劣ります。同時に、JavaScript はブラウザなどの厳しく制限された環境で実行されます。したがって、開発者はクライアント側でどのロジックを実行できるかを明確に理解する必要があります。
実際のアプリケーションでクライアント側プログラミングをどのように使用するかは、開発者の経験と判断によって異なります。ここでの多くの問題は理解することしかできません。紙面の都合上、ここでは以下の注意事項を大まかにまとめます。
ループ本体内でリモートプロシージャコールを使用しないなど、リモートプロシージャコールの多用はできるだけ避けてください。
可能であれば、AJAX リモート プロシージャ コール (非同期リモート プロシージャ コール) を使用します。
クライアント側に大量のデータ操作を配置しないようにします。例: データ コピー操作の大規模なバッチ、大量のデータ トラバーサルを必要とする計算など。
DOMオブジェクトの操作方法を改善します。
クライアント側プログラミングでは、DOM オブジェクトに対する操作が CPU 時間を最も占有する可能性が高くなります。 DOM オブジェクトの操作では、さまざまなプログラミング方法間のパフォーマンスの差が非常に大きくなることがよくあります。
以下は、まったく同じ結果をもたらす 3 つのコードです。それらの機能は、Web ページに 10x1000 のテーブルを作成することです。ただし、走行速度は大きく異なります。
/* テストコード 1 - 所要時間: 41 秒*/
var table = document.createElement("TABLE");
document.body.appendChild(テーブル);
for(var i = 0; i < 1000; i++){
var row = table.insertRow(-1);
for(var j = 0; j < 10; j++){
var cell = objRow.insertCell(-1);
cell.innerText = "( " + i + " , " + j + " )";
}
}
/* テストコード 2 - 所要時間: 7.6 秒*/
var table = document.getElementById("TABLE");
document.body.appendChild(テーブル);
var tbody = document.createElement("TBODY");
table.appendChild(tbody);
for(var i = 0; i < 1000; i++){
var row = document.createElement("TR");
tbody.appendChild(行);
for(var j = 0; j < 10; j++){
var cell = document.createElement("TD");
row.appendChild(セル);
cell.innerText = "( " + i + " , " + j + " )";
}
}
/* テストコード 3 - 所要時間: 1.26 秒*/
var tbody = document.createElement("TBODY");
for(var i = 0; i < 1000; i++){
var row = document.createElement("TR");
for(var j = 0; j < 10; j++){
var cell = document.createElement("TD");
cell.innerText = "( " + i + " , " + j + " )";
row.appendChild(セル);
}
tbody.appendChild(行);
}
var table = document.getElementById("TABLE");
table.appendChild(tbody);
document.body.appendChild(テーブル);
ここでの「テスト コード 1」と「テスト コード 2」の違いは、表のセルを作成するときに使用される API メソッドが異なることです。 「テストコード 2」と「テストコード 3」の違いは、処理順序が若干異なることです。
「テスト コード 1」と「テスト コード 2」のそれほど大きなパフォーマンスの違いを分析することはできません。現時点でわかっているのは、insertRow と insertCell は DHTML のテーブル固有の API であり、createElement と appendChild は W3C DOM のネイティブ API であるということです。前者は後者をカプセル化する必要があります。ただし、このことから、DOM のネイティブ API が常にオブジェクト固有の API よりも優れていると結論付けることはできません。 API を頻繁に呼び出す必要がある場合は、パフォーマンスに関する基本的なテストを実行することをお勧めします。
「テスト コード 2」と「テスト コード 3」のパフォーマンスの違いは、主にビルド順序の違いに起因します。 「テスト コード 2」のアプローチは、最初に最も外側の <TABLE> オブジェクトを作成し、次にループ内で <TR> と <TD> を順番に作成することです。 「テスト コード 3」のアプローチは、まずメモリ内にテーブル全体を内側から外側に構築し、次にそれを Web ページに追加することです。この目的は、ブラウザがページ レイアウトを再計算する回数をできる限り減らすことです。 Web ページにオブジェクトを追加するたびに、ブラウザはページ上のコントロールのレイアウトを再計算しようとします。したがって、まずメモリ内に構築するオブジェクト全体を作成し、それを一度に Web ページに追加できればよいのです。その後、ブラウザはレイアウトの再計算のみを実行します。一言でまとめると、appendChild の実行は遅いほど良いということです。場合によっては、操作効率を向上させるために、removeChild を使用してページから既存のコントロールを削除し、構築が完了した後でそれをページに再配置することを検討することもできます。
AJAX を使用して情報を送信する場合、XmlHttp を介して POST 送信を完了するために、いくつかの比較的大きな文字列を組み立てる必要がある場合があります。これほど大量の情報を提出するのは上品ではないように思えるかもしれませんが、時にはそのような必要に直面しなければならない場合もあります。では、JavaScript での文字列の蓄積はどれくらいの速度で行われるのでしょうか?まずは次の実験をしてみましょう。長さ 30000 の文字列を蓄積します。
/* テスト コード 1 - 所要時間: 14.325 秒*/
var str = "";
for (var i = 0; i < 50000; i++) {
str += "xxxxxx";
}
このコードには 14.325 秒かかり、結果は理想的ではありませんでした。次に、コードを次の形式に変更します。
/* テストコード 2 - 所要時間: 0.359 秒*/
var str = "";
for (var i = 0; i < 100; i++) {
var サブ = "";
for (var j = 0; j < 500; j++) {
サブ += "xxxxxx";
}
str += サブ;
}
このコードには 0.359 秒かかります。結果は同じで、最初に小さな文字列をいくつかアセンブルしてから、より大きな文字列にアセンブルするだけです。このアプローチにより、文字列アセンブリの後の段階でメモリにコピーされるデータの量を効果的に削減できます。この原則を理解した後、テストのために上記のコードをさらに分解することができます。以下のコードは 0.140 秒しかかかりません。
/* テスト コード 3 - 所要時間: 0.140 秒*/
var str = "";
for (var i1 = 0; i1 < 5; i1++) {
var str1 = "";
for (var i2 = 0; i2 < 10; i2++) {
var str2 = "";
for (var i3 = 0; i3 < 10; i3++) {
var str3 = "";
for (var i4 = 0; i4 < 10; i4++) {
var str4 = "";
for (var i5 = 0; i5 < 10; i5++) {
str4 += "xxxxxx";
}
str3 += str4;
}
str2 += str3;
}
str1 += str2;
}
str += str1;
}
ただし、上記のアプローチは最善ではない可能性があります。送信する必要がある情報が XML 形式である場合 (実際、ほとんどの場合、送信する情報を XML 形式に組み立てることができます)、DOM オブジェクトを使用して組み立てる、より効率的で洗練された方法を見つけることもできます。私たちの文字列。次の段落では、長さ 950015 の文字列を組み立てるのにわずか 0.890 秒しかかかりません。
/* DOM オブジェクトを使用して情報を組み立てます - 所要時間: 0.890 秒*/
var xmlDoc;
if (browserType == BROWSER_IE) {
xmlDoc = new ActiveXObject("Msxml.DOMDocument");
}
それ以外 {
xmlDoc = document.createElement("DOM");
}
var root = xmlDoc.createElement("root");
for (var i = 0; i < 50000; i++) {
var ノード = xmlDoc.createElement("データ");
if (browserType == BROWSER_IE) {
ノード.テキスト = "xxxxxx";
}
それ以外 {
ノード.innerText = "xxxxxx";
}
root.appendChild(ノード);
}
xmlDoc.appendChild(root)
;
if (browserType == BROWSER_IE) {
str = xmlDoc.xml;
}
それ以外 {
str = xmlDoc.innerHTML;
DOM オブジェクトのメモリリークを回避します。
IE における DOM オブジェクトのメモリ リークは、開発者によって無視されることが多い問題です。しかし、それがもたらす結果は非常に深刻です。これにより、IE のメモリ使用量が増加し続け、ブラウザの全体的な実行速度が大幅に低下します。一部の深刻な漏洩 Web ページでは、数回更新しただけでも実行速度が 2 倍になります。
より一般的なメモリ リーク モデルには、「循環参照モデル」、「クロージャ関数モデル」、「DOM 挿入順序モデル」が含まれます。最初の 2 つのリーク モデルについては、Web ページが破棄されたときに逆参照することで回避できます。 「DOM 挿入オーダー モデル」に関しては、一般的なプログラミングの習慣を変更することで回避する必要があります。
メモリ リーク モデルの詳細については、Google を検索するとすぐに見つかります。この記事では詳しく説明しません。ただし、ここでは、Web ページのメモリ リークを見つけて分析するために使用できる小さなツール、Drip をお勧めします。現在の新しいバージョンは 0.5 で、ダウンロード アドレスはhttp://outofhanwell.com/ieleak/index.phpです。
複雑なページのセグメント化された読み込みと初期化 システム内の非常に複雑で IFrame を使用するのが不便な一部のインターフェイスについては、セグメント化された読み込みを実装できます。たとえば、複数ページのタブ インターフェイスの場合、最初に複数ページ タブのデフォルト ページをダウンロードして初期化し、次に AJAH (非同期 JavaScript および HTML) テクノロジを使用して、他のタブ ページのコンテンツを非同期的に読み込むことができます。これにより、最初からインターフェイスをユーザーに表示できることが保証されます。複雑なインターフェース全体の読み込みプロセスをユーザーの操作プロセスに分散します。
GZIP を使用してネットワーク トラフィックを圧縮します。
上記のコードレベルの改善に加えて、GZIP を使用してネットワーク トラフィックを効果的に削減することもできます。現在、すべての一般的な主流ブラウザはすでに GZIP アルゴリズムをサポートしています。多くの場合、GZIP をサポートするには少量のコードを記述するだけで済みます。たとえば、J2EE では、Filter で次のコードを使用して、クライアント ブラウザが GZIP アルゴリズムをサポートしているかどうかを判断し、必要に応じて java.util.zip.GZIPOutputStream を使用して GZIP 出力を実装できます。
/* ブラウザが GZIP をサポートする方法を決定するコード*/
private static String getGZIPEncoding(HttpServletRequest request) {
String acceptEncoding = request.getHeader("Accept-Encoding");
if (acceptEncoding == null) は null を返します。
acceptEncoding = acceptEncoding.toLowerCase();
if (acceptEncoding.indexOf("x-gzip") >= 0) "x-gzip" を返します。
if (acceptEncoding.indexOf("gzip") >= 0) "gzip" を返します。
null を返します。
}
一般に、HTML および JSP の GZIP の圧縮率は約 80% に達することがあり、それによってサーバーとクライアントに生じるパフォーマンスの損失はほとんど無視できます。他の要因と組み合わせると、GZIP をサポートする Web サイトによってネットワーク トラフィックが 50% 節約される可能性があります。したがって、GZIP を使用すると、ネットワーク環境があまり良くないアプリケーションのパフォーマンスが大幅に向上します。 HTTP監視ツールFiddlerを利用すると、GZIP利用前後のWebページの通信データ量を簡単に検出できます。 Fiddler のダウンロード アドレスはhttp://www.fiddlertool.com /fiddler/ です。
Web アプリケーションのパフォーマンスの最適化は、実際には非常に大きなトピックです。スペースが限られているため、この記事では詳細の一部しか説明できず、これらの詳細の最適化方法を完全に示すこともできません。この記事が Web アプリケーション、特にクライアント側のパフォーマンスの最適化に皆さんの注目を集めることができれば幸いです。結局のところ、サーバーサイドのプログラミング技術は長年にわたって誰にでも知られており、サーバーサイドのパフォーマンスを活用する可能性はあまりありません。クライアント側でメソッドを改善すると、多くの場合、驚くべきパフォーマンスの向上が得られます。