効率的な Web フロントエンド プログラムを作成する方法は、フロントエンド開発を行うたびに無意識に考える問題です。数年前、Yahoo の優秀なフロントエンド エンジニアが Web フロントエンドのパフォーマンス向上に関する本を出版し、Web 開発テクノロジ コミュニティ全体にセンセーションを巻き起こしました。この謎の Web フロントエンド最適化問題は、Web 上で一般的な問題となりました。業界全体が衝撃的な秘密の答えを知ったとき、Web フロントエンドの最適化は、開発する Web サイトに質的な飛躍をもたらすことができなくなります。私たちが開発する Web サイトのパフォーマンスを他の Web サイトよりも向上させる 私たちの Web サイトをより良くするには、より深く独立して考え、より優れたスキルを確保する必要があります。
Javascript のイベント システムが最初に思い浮かぶブレークスルー ポイントです。なぜ JavaScript イベント システムなのか? Web フロントエンドには html、css、javascript という 3 つのテクノロジーが含まれていることは誰もが知っています。html と css がどのように組み合わされるかは非常に明確です。これについてはあまり説明できませんが、どのように組み合わされるのかは明らかです。 JavaScript は html と css の間に入るのですが、この 3 つを統合するのはどうでしょうか?最後に、このエントリポイントは JavaScript のイベント システムであることがわかり、どんなに長く複雑な JavaScript コードを書いても、最終的にはイベント システムを介して HTML や CSS に反映されるということが分かりました。が 3 つのポイントを統合するためのエントリ ポイントである場合、特に今日のますます複雑化している Web ページでは、ページ内に必然的に多数のイベント操作が存在することになります。これらのイベントがなければ、慎重に作成された JavaScript コードは にのみ保存されます。データベースを削除すると、主人公は役に立たなくなります。ページ上には多数のイベント関数が存在することになるため、習慣に従ってイベント関数を作成した場合、効率に影響を与える問題はありますか?私が調査した答えは、実際には効率の問題があり、また深刻な効率の問題でもあるということです。
私の答えを明確に説明するには、まず JavaScript イベント システムについて詳しく説明する必要があります。
イベント システムは、JavaScript、HTML、CSS を統合するためのエントリ ポイントです。このエントリ ポイントは、Java の main 関数のようなものです。では、ブラウザはどのようにしてこのエントリを完成させるのでしょうか。合計 3 つの方法を調査しました。
方法 1: HTML イベント処理
HTMLイベント処理とは、htmlタグ内にイベント関数を直接記述することです。この記述方法はhtmlタグと密接に結合しているため、htmlイベント処理と呼ばれます。たとえば、次のコード:
クリックイベント関数が複雑な場合、このようにコードを書くと確実に不便になるため、関数を外部に記述し、onclick が関数名を直接呼び出すことがよくあります。例:
方法 2: DOM レベル 0 イベント処理
DOM0 レベルのイベント処理は、現在すべてのブラウザーでサポートされているイベント処理です。互換性の問題はありません。このような文を見ると、Web フロントエンドに携わるすべての人が興奮するでしょう。 DOM0 イベント処理のルールは次のとおりです。各 DOM 要素には独自のイベント処理属性があり、次のコードのような関数を割り当てることができます。
次のコードをもう一度見てください:
DOM2 イベント処理は標準化されたイベント処理ソリューションですが、IE ブラウザは独自のセットを開発しました。機能は DOM2 イベント処理に似ていますが、コードは異なります。 方法 3 を説明する前に、いくつかの概念を追加する必要があります。そうしないと、方法 3 の意味を明確に説明できなくなります。
最初のコンセプト: イベントフロー
ページの開発では、このような状況によく遭遇します。JavaScript では、ページの作業領域は、ドキュメント要素をカバーすることに相当します。 div 内の button 要素。button 要素は div をカバーし、これはドキュメントをカバーすることと同じです。したがって、問題は、ボタンをクリックすると、クリック動作がボタン上で発生するだけでなく、クリック操作が発生することです。これら 3 つのロジック要素は、クリック イベントをトリガーできます。イベント フローは、上記のシナリオを説明する概念です。イベントがページから受信される順序を意味します。
2 番目の概念: イベント バブリングとイベント キャプチャ
イベント バブリングはイベント フローの問題を解決するために Microsoft によって提案されたソリューションであり、イベント キャプチャは Netscape によって提案されたイベント フロー ソリューションです。
Microsoft は、バブリング イベントに基づいた新しいイベント システムを設計しました。これは、業界では一般に IE イベント処理と呼ばれています。IE イベント処理メソッドは、次のコードに示すとおりです。
コードをコピーします実行後、両方のダイアログ ボックスが正常に表示されます。この方法を使用すると、DOM 要素に複数の異なるクリック イベントを追加できます。イベントを希望しない場合はどうすればよいですか? Internet Explorer にはイベントを削除するための detachEvent メソッドが用意されており、クリック イベントを削除する場合は、次のように同じパラメータを渡すだけです。次のコード内:
これを実行すると、2 番目のクリックが削除されず、非常に混乱します。イベントの削除にはイベントの追加と同じパラメータが必要であると前述しましたが、JavaScript の匿名関数では、2 つの匿名関数のコードがまったく同じであっても、JavaScript は内部的に異なる変数を使用してそれを格納することになります。私たちが見ている現象はクリック イベントの削除ではないため、コードは次のように記述する必要があります:
追加メソッドと削除メソッドは同じオブジェクトを指しているため、イベントは正常に削除されます。このシーンは、イベントを記述するときに良い習慣を持つべきであること、つまり、動作関数を独立して定義する必要があり、習慣として匿名関数を使用しないことを示しています。
次のステップは DOM2 イベント処理です。その原理を次の図に示します。
DOM2 は標準化されたイベントです。DOM2 イベントを使用すると、最初にキャプチャ メソッド、つまりドキュメントからイベントが中間点に到達すると、イベントが配信されます。がターゲット ステージにあり、イベントがターゲット ステージに入ります。その後、イベントが泡立ち始め、最終的にドキュメント上でイベントが終了します。 (キャプチャイベントの開始点もバブリングイベントの終了点もすべてドキュメントを指しています。ブラウザによってはウィンドウからキャプチャを開始してバブリングを終了してしまう場合もあるのが現状です。ただし、ブラウザ自体は開発中に設定されますが、ドキュメントに注目することは開発にとってより有意義なので、ここでは常にドキュメントを使用します)。バブリング イベントは開発でより広く使用されているため、人々はターゲット ステージをバブリングの一部として分類することに慣れています。
DOM2 のイベント処理は、イベントがトリガーされるたびにすべての要素を 2 回走査するため、IE の場合は 1 回の走査だけで済むため、パフォーマンスは大幅に低下します。これがないからといって、開発と設計の観点から見ると、両方のイベント システムをサポートすることで開発の柔軟性が向上するというわけではありません。この観点から見ると、DOM2 イベントは依然として非常に有望です。 DOM2 イベントのコードは次のとおりです:
DOM2 イベント処理でイベントを追加するには、addEventListener が使用されます。これは ie イベント処理メソッドの 2 つのパラメーターと同じ意味を持ちます。最初のパラメータは削除する必要があります。3 番目のパラメータはブール値です。値が true の場合、イベントはキャプチャ メソッドに従って処理されます。 3 番目のパラメータを使用すると、DOM2 イベント処理でイベント要素を 2 回実行する必要があることがわかります。ただし、ここで注意していただきたいのは、キャプチャまたはバブルのどちらを選択しても、 2 つのトラバースは永久に実行されます。1 つのイベント処理方法を選択すると、別のイベント処理プロセスではイベント処理関数はトリガーされません。これは、車がニュートラルでアイドリングしているのと同じです。 DOM2 イベント メソッドの設計を通じて、DOM2 イベントは実行時に 2 つのイベント処理メソッドのうち 1 つだけを実行できることがわかりました。したがって、要素は 2 回トラバースされますが、2 つのイベント ストリーム システムが同時にトリガーされることは不可能です。 2 回トリガーされないという場合、実際には、次のコードのように 2 つのイベント フロー モデルの同時実行をシミュレートできます。 🎜>
DOM2 にはイベントを削除する関数も用意されており、この関数は次のように記述されます。
それを実行すると、イベントが正常に削除されていないことがわかります。
最後に言いたいのは、IE9 では DOM2 イベント処理が十分にサポートされており、IE9 以降では DOM2 イベントがサポートされていないということです。
次のように 3 つのイベント メソッドを比較してみましょう:
比較 1: 方法 1 を他の 2 つの方法と比較します
方法 1 は、HTML と JavaScript を組み合わせて記述します。この方法をさらに深めるのが、HTML と JavaScript の混合開発です。コード結合です。これは初心者プログラマのレベルなので、最初の方法は完全に敗北し、他の 2 つの方法は完全に敗北しています。
比較 2: 方法 2 と方法 3
2 つの書き方は似ていますが、どちらが優れているか、どちらが悪いかを判断するのは非常に難しい場合があります。上記の内容を見ると、方法 2 と方法 3 の最大の違いは次のとおりです。 2 つ目は、DOM 要素が特定のイベントを持つことができるのは 1 回だけであるということです。方法 3 では、DOM 要素の特定のイベントに複数のイベント処理機能を持たせることができます。したがって、方法 3 では、イベント フローを正確に制御することもできます。方法 3 は方法 2 よりも強力なので、比較すると、方法 3 の方がわずかに優れています。
この記事の焦点は次のとおりです: イベント システムのパフォーマンスの問題を解決するには、次の 2 つの焦点からイベント システムのパフォーマンスの問題を考えます。 : 走査回数とメモリ消費量を削減します。
1 つ目は、キャプチャ イベント ストリームであってもバブリング イベント ストリームであっても、要素は走査されますが、要素間の親子関係がある場合、走査は上部のウィンドウまたはドキュメントから開始されます。ページ DOM 要素が深いと、トラバーサルが行われます。DOM2 イベント処理のように、要素が増えるほど、トラバーサルの危険性が高まります。このイベント ストリーム トラバーサルの問題を解決するにはどうすればよいでしょうか。私の答えはノーです。ここにいる友人の中には疑問を持っている人もいるかもしれませんが、なぜもう何もないのですか?イベント システムにはイベント オブジェクトがあり、このオブジェクトにはイベントのバブリングやキャプチャを防ぐメソッドがあります。この友人の質問は非常に合理的ですが、この方法を使用してトラバースを減らしたい場合は、親要素と子要素の間の関係、およびネストされた要素が多数ある場合には、祖父要素と孫要素の間の関係をコードで処理する必要があります。したがって、私の答えは、トラバースの問題を変更することはできず、それに適応することしかできない、ということです。
トラバーサルを減らしてもイベント システムのパフォーマンスの問題は解決できないようです。そのため、現在考慮すべき点はメモリ消費だけです。 C# は使いやすいという意見をよく聞きますが、Web フロントエンド開発にはさらに優れています。ボタンがページに到達すると、JavaScript コードが自動的に実行されます。もちろん、内部のイベント関数は空の関数なので、この方法で 100 個のボタンをページに配置できると考えました。これは、100 個のボタン イベント ハンドラーを持つことになります。最後に、ボタンの 1 つに特定のボタンを追加しました。このページは効率的ですか? JavaScript では、各関数はオブジェクトであり、各オブジェクトはメモリを消費するため、これらの無駄な 99 個のイベント関数コードはブラウザの貴重なメモリを大量に消費することになります。もちろん、実際の開発環境ではこれを行いませんが、ajax が人気があり、シングルページ開発が非常に人気のある今日の時代では、Web ページ上には非常に多くのイベントがあります。つまり、各イベントにはただし、実行する各操作は 1 つのイベントのみをトリガーします。この時点では、他のイベントは実行されず、コンピューターのメモリを消費します。
この状況を変えるには解決策が必要であり、実際にそのような解決策は存在します。このソリューションを明確に説明するために、最初にいくつかの背景知識を追加する必要があります。DOM2 イベント処理を説明するときに、DOM2 イベント処理メソッドとは別に、キャプチャ イベントにもターゲット オブジェクトの概念があります。処理およびバブリング イベント処理では、ターゲット オブジェクトはイベントの特定の操作の DOM 要素です。たとえば、ボタンのクリック操作では、イベント処理メソッドに関係なく、ボタンがターゲット オブジェクトになります。イベント オブジェクトには属性 target があり、ターゲットは常にターゲット オブジェクトを指します。また、イベント オブジェクトには、キャプチャされたイベントまたはバブリング イベントのフロー先となる DOM 要素を指す currentTarget というプロパティもあります。上記の説明から、キャプチャ イベントであってもバブリング イベントであっても、ドキュメントにクリック イベントを追加しても、ページ上のボタンはクリック イベントを追加しないことがわかります。この時点で、ボタンをクリックすると、ドキュメントのクリック イベントがトリガーされることがわかります。ドキュメントのクリック イベントがトリガーされると、イベントのターゲットはドキュメントではなくボタンになるということです。次のようなコードを書くことができます:
実行すると、ボタンイベントを個別に記述した場合と同じ効果が得られることがわかります。しかし、その利点は明らかです。1 つの関数がページ全体のイベント関数を処理し、アイドル状態のイベント関数はありません。このソリューションには、イベント委任という専門的な名前もあります。 jQuery のデリゲート メソッドはこの原則に基づいています。実際、イベント委任の効率はイベント関数の削減に反映されるだけでなく、DOM トラバーサル操作も削減できます。たとえば、上記の例では、ドキュメントがトップレベルのオブジェクトです。特定のオブジェクト イベントに関しては、DOM 操作を使用せず、イベント オブジェクトの target 属性を使用します。これはすべて、次の 1 つの文に要約できます。本当に速いです、理由もなく速いです。
イベント委任は、素晴らしい副産物ももたらします。jQuery を使用したことがある友人は、ライブ メソッドを使用しているはずです。ライブ メソッドの特徴は、この要素にイベント操作を追加できないことです。イベント委任の仕組みを理解すると、実際に jQuery のライブはイベント委任によって行われ、ライブも効率的に追加できます。イベント。
イベント委任を理解すると、jQuery のバインド メソッドはオリジナルのイベント定義メソッドを使用するため非効率なメソッドであることがわかります。実際、新しいバージョンの jQuery 開発者もこの問題に気づいています。 jQuery には on メソッドがあり、on メソッドにはバインド、ライブ、デリゲート メソッドのすべての機能が含まれているため、この記事を読んだ友人は、イベントを追加する以前の方法を放棄して、on 関数を使用することをお勧めします。
上記のイベント委任の例では、ドキュメントにイベントを追加しました。ここで、jQuery では、ready メソッドに DOM 要素のイベントの定義を入れることに慣れています。 、次のように表示されます:
ready 関数は、ページ DOM ドキュメントが読み込まれた後に実行され、onload 関数の前に実行されます。この利点の 1 つは、jQuery などのイベント定義でも実行されることです。一部の友人は、特定のイベント バインディングを外部に準備し、ボタンが無効になることが時々あることに気づきました。そのため、私たちはこの問題の原則を無視して実行することがよくあります。この操作は実際には、DOM がロードされる前にイベントをバインドするためのものであり、この期間中に一部の要素がページ上に構築されていないため、イベント バインディングは行われません。したがって、イベント定義の原則は、ページのすべての要素がロードされた後に DOM 要素のイベントが定義されていることを確認することです。ただし、イベント委任を使用する場合など、問題は回避できます。はページ全体を表すため、読み込まれた時間が最も早いため、ドキュメント内でイベントデリゲーションを実装することで、イベントが無効になりにくく、またブラウザから「XXX関数が無効です」と報告されにくくなります。定義されています。」この機能を要約すると、イベント委任コードはページ読み込みのどの段階でも実行できるため、開発者は Web ページのパフォーマンスを向上させたり、Web ページの効果を強化したりする自由度が高まります。
これでこの記事は書き終わりました。おやすみ。