Javascript
 Computer >> コンピューター >  >> プログラミング >> Javascript

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

初心者向けで実用的なVanillaJavaScriptチュートリアル。重要なポイント:高性能ウィンドウイベントの書き方 ユーザーのハードウェアを破壊することはありません。

対象:完全な初心者から中級者

今日は、「ビューポートディメンション」と呼ばれるすばらしい小さなアプリを作成しています。 この機能は非常に効果的です。ブラウザウィンドウのサイズを変更すると、ブラウザのビューポートの幅と高さの値が表示されます。

レスポンシブデザインを行う場合、これは非常に貴重なツールです。 CodePenにも同様の機能があります。しかし、もっと大きなものといくつかの追加機能が必要だったので、自分で作成することにしました。その過程で、特にパフォーマンスの問題を処理する方法について、たくさんのことを学びました。今、私はあなたとそれを共有しています!

ビューポートの寸法

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

私はあなたの既存の知識について推測したくありません。結果として、これは非常に詳細な チュートリアル。

技術トピック:

  • createElement()を使用して要素を作成する方法 メソッド。
  • Styleオブジェクトを使用して要素のスタイルを設定する方法
  • ウィンドウオブジェクトのresizeを設定して使用する方法 イベント。
  • innerWidth を使用して、ブラウザのビューポートから幅と高さを取得する方法 およびinnerHeight プロパティ。
  • 関数の外部で関数を呼び出す方法(コールバック)。
  • 条件付き(true / false) if ステートメントは機能します。
  • setTimeout()を使用して、タイマーでコードの実行を遅らせる方法
  • clearTimeout()を使用してタイマーをリセットする方法 。
  • イベントスロットル機能の使用方法 ウィンドウイベントのパフォーマンスを劇的に向上させるため。
  • MSとFPSの関係 (ミリ秒と1秒あたりのフレーム数)
  • 知覚されるパフォーマンスの重要な違い およびハードウェアパフォーマンス。

アプローチ

ビューポートディメンションアプリの2つのバージョンを作成しています。

  • バージョン1 アプリを機能させることです。これはドラフトですが、最終製品ではありません。
  • バージョン2 バージョン1を改善することです。コードのパフォーマンスを高め、エネルギー効率を高め、読みやすくする方法を学びます。

JavaScript中心の状態を維持するために、すべてを実行します JavaScriptコードで。すべてを1つのJavaScriptファイルに保存することで、アプリを既存のプロジェクトに簡単に追加することもできます。

あなたは完全な初心者ですか? 次に、CodePenを使用してフォローすることをお勧めします。使用するためにサインアップする必要はありません。ここで視聴できる非常に人気のあるCodePenビデオチュートリアルを公開しました。

学ぶ方法

混乱している場合は、数段落前に戻って、重要なことをスキップしていないことを確認してください。自分で問題を解決しようとすることで、より多くのことを学ぶことができます 次に、参照コード second を探します 。

迷子になった場合 完成したコードはいつでも参照できます:

  • バージョン1
  • バージョン2

始めましょう!

ビューポートの寸法[バージョン1.0]

コーディングを始める前に、プロジェクトの要件を見てみましょう。

要件

  • ウィンドウの幅と高さを表示するためのコンテナが必要です。
  • ウィンドウの右上隅に配置する必要があります。
  • デフォルトで非表示にする必要があります。
  • ウィンドウのサイズが変更されるとすぐに表示されます。
  • 最新のウィンドウサイズ変更から3秒後に非表示になります。

これがバージョン1の機能要件の本質です。

コーディングを始めましょう!

ディスプレイコンテナの作成とスタイリング

まず、 createElement を使用して、ビューポートディメンションアプリのdiv要素を作成しましょう。 メソッドとそれを変数に割り当てます:

var viewportDimensions = document.createElement("div");

これで、空の

ができました。 変数内に格納されている要素。

ブラウザでは、すべてのHTML要素は要素オブジェクトで表されます。 これらのElementオブジェクトにはプロパティがあります およびメソッド JavaScriptでアクセスできます。

ビューポートの幅と高さをブラウザウィンドウの右上隅に表示する必要があります。それを処理し、HTML DOMStyleオブジェクトにアクセスしてdiv要素にスタイルを設定しましょう。 プロパティ:

viewportDimensions.style.position = "fixed";
viewportDimensions.style.right = "0";
viewportDimensions.style.top = "0";
viewportDimensions.style.padding = "16px";
viewportDimensions.style.zIndex = "3";
viewportDimensions.style.fontSize = "22px";

上記の構文はドット表記です。 簡単に言うと、を使用することを意味します。 オブジェクトのプロパティまたはメソッドにアクセスします。したがって、上記の例では、次のように言っています。

  • ねえviewportDimensions
  • スタイルオブジェクトへのアクセスを許可してください
  • そのため、スタイリングプロパティにアクセスできます

Styleオブジェクトを使用したスタイリングは、CSSを使用したスタイリングに似ています。ただし、Styleオブジェクトはインラインスタイルを使用します。 スタイリングプロパティは、外部のCSSスタイルシートではなく、HTML要素に直接追加されます。

ビューポートの寸法

を追加して、コードが機能することを確認しましょう への要素 HTMLドキュメントの要素。

まず、ドキュメントのbody要素への参照を格納する変数を宣言しましょう。 JavaScriptファイルの先頭に次のコードを追加します。

var body = document.querySelector("body");

次に、body要素内にビューポートディメンションのdiv要素を追加しましょう。 JavaScriptファイルの最後(最後のスタイルの下)に次のコードを配置します:

body.appendChild(viewportDimensions);

appendChild() メソッドです 別のノード内にノードを追加(追加)します。 すべて DOMにはノードがあり、さまざまな種類のノードがあります。この場合、body要素ノード内にdiv要素ノードを追加します。

div要素にはまだコンテンツが含まれていないため、現在のコードが機能するかどうかを確認することはできません。要素に一時的な境界線を追加することで、すぐにわかります:

viewportDimensions.style.border = "10px solid";

正常に機能する場合は、ウィンドウの右上隅に太い黒の境界線が付いた小さなボックスが表示されます。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

ブラウザウィンドウを右クリックして確認することもできます。次に、検査をクリックします ブラウザのDevToolsにアクセスします。

次に、[要素]タブで、 bodyを見つけます。 要素を指定すると、いくつかのインラインスタイルプロパティを含む空のdiv要素が表示されます。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する DevToolsでマウスを上に移動すると、右上隅に非表示のdivが強調表示されることに注意してください。

これまでのすべてのコードの概要は次のとおりです。

// Select body element
var body = document.querySelector("body");

// Create div element
var viewportDimensions = document.createElement("div");

// Style element
viewportDimensions.style.position = "fixed";
viewportDimensions.style.right = "0";
viewportDimensions.style.top = "0";
viewportDimensions.style.padding = "16px";
viewportDimensions.style.zIndex = "3";
viewportDimensions.style.fontSize = "22px";

// Add div element inside body element
body.appendChild(viewportDimensions);

すばらしいです。div要素が作成され、スタイルが設定され、body要素内に追加されました。次はウィンドウサイズ変更イベントです。

ウィンドウサイズ変更イベントの設定

Windowオブジェクトは、ブラウザウィンドウを表します。 addEventListenerを含むいくつかのメソッドがあります 。このメソッドは、多くのタイプをリッスンできます。 スクロール、クリック、入力、サイズ変更などのウィンドウイベントの一覧。

'resize'を使用します イベント。 body.appendChildの下 以下を追加します:

window.addEventListener("resize", function() {
  // Code to execute when window resizes
});

注:コメント // ブラウザによって解釈されるのではなく、私たち人間のためだけに存在します

以前は、ドット表記を使用してdiv要素のプロパティを取得しました。これを使用して、メソッドにアクセスします。 ウィンドウオブジェクト: addEventListener

2つの引数を渡します イベントリスナーへ:'resize' およびfunction() 。サイズ変更イベントについてはすでに説明しましたが、その機能は何ですか?

function() ウィンドウサイズ変更イベントがアクティブになるたびに(ウィンドウのサイズを変更するとすぐに)実行するコードブロックを設定します。コードブロックは、中括弧 {}の中にあるものです。 (機能本体とも呼ばれます) これまでのところ、//コメントしかありません 。

ウィンドウイベントを呼び出すたびに、 function()に通知します。 中括弧内のコードを実行するには{}

動作していることを確認するために、 console.log()を使用してテストしてみましょう。 :

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  console.log("Working!");
});

次に、ウィンドウのサイズを変更します。コンソールに「Working!」と表示された場合何度も、それはあなたのウィンドウサイズ変更イベントが機能していることを意味します。

コンソールへのアクセス

CodePenでコンソールにアクセスするには、ウィンドウの左下隅にある[コンソール]ボタンをクリックします。 Chromeでコンソールにアクセスするには、キーボードショートカットを次に示します。

  • Cmd + Opt + J(Mac)。
  • Ctrl + Shift + J(Windows / Linux)

了解しました。ウィンドウイベントを機能させましょう!

ブラウザの幅と高さをピクセル単位で返す

次の動きは、ビューポートの幅と高さの数値を取得することです。ウィンドウのサイズを変更するときに、値を即座に更新する必要があります。 ウィンドウオブジェクト ブラウザウィンドウを表します。 innerWidthと呼ばれるいくつかの素晴らしいプロパティがあります およびinnerHeight

彼らが何をしていると思いますか?

はい、ブラウザウィンドウの幅と高さをピクセル単位で返します(スクロールバーを含む)。これを確認して、 console.log()を使用しましょう これらの幅と高さのプロパティ値を返します。

現在の値を動的に取得する必要があるため console.log()を配置する必要があります は、サイズ変更イベントの機能ブロック内にあります:

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  console.log("Width:", window.innerWidth);
  console.log("Height:", window.innerHeight);
});

'幅:' および'Height:' console.log()のテキスト は、コンソール出力を明確にするためだけにあります。

実際には、window。を作成する必要はありません。 幅と高さの値を取得するには、 innerWidth およびinnerHeight 動作します。混乱を避けるためにそうします。

それが機能する場合、ブラウザウィンドウのサイズを変更する限り、コンソールは常に現在のビューポートのサイズを印刷します。

次のようになります:

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

今、私たちはどこかに到達しています!

console.log()を取り除きましょう 代わりに、widthプロパティとheightプロパティを独自の変数に割り当てて、それらへの参照を保存できるようにします。

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  var width = window.innerWidth;
  var height = window.innerHeight;
});

width およびheight ウィンドウの幅と高さのプロパティの現在の値が常に含まれます。 常に 戻り値を変数に割り当てる必要がありますが、後でその情報を使用または変更できるため、これは良い習慣です。

新しい変数が正常に機能することを確認するには、それらの新しい変数をコンソールに出力してみてください。

window.addEventListener("resize", function() {
  // Code to execute when window resizes
  var width = window.innerWidth;
  var height = window.innerHeight;

  console.log(width);
  console.log(height);
});

すべてが機能する場合は、console.logを削除して、次に進むことができます。

div要素に幅と高さの値を追加する

返された幅と高さの値をdiv要素に追加します。具体的には、値を内部に埋め込みます。 div要素の開始タグと終了タグ:

<div> We want width & height values here </div>

これを行うには、div要素を格納する変数 viewportDimensionsを取得する必要があります。 。次に、 textContentという要素オブジェクトのプロパティにアクセスする必要があります。 。以前と同じドット表記を使用します:

viewportDimensions.textContent;

次に、幅と高さの変数を割り当てる必要があります。

viewportDimensions.textContent = width + "px" + " x " + height + "px";

今すぐブラウザウィンドウのサイズを変更してみてください。すべてを正しく行うと、ウィンドウの右上隅に現在の幅と高さの値が表示されます。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

上で使用したコード構文は少し混乱しているように見えるかもしれません。

分解してみましょう:

textContent 要素オブジェクトのプロパティです。ビューポートの寸法div要素を含め、ドキュメント内のすべての要素にそれがあります。

textContent ノードを返します 具体的には、テキストノード 。例:段落要素内のテキスト:

一部のテキスト...

、はテキストノードです。

viewportDimensions 変数に空の

が含まれていました エレメント。これで、開始div要素タグと終了div要素タグの間に数値のピクセル値を持つテキストノードが返されます。

width + "px" + " x " + height + "px";

およびheight どちらにもピクセル値が含まれています。 'px'のみを追加します および'x' (文字列)幅と高さの変数を分離し、返される値がピクセル単位であることをすべての人に明確にするため。

setTimeout()を使用したカウントダウンタイマーの追加

ウィンドウのサイズを変更していないときに、幅と高さが常に表示されることは望ましくありません。ブラウザウィンドウのサイズ変更を停止してからちょうど3秒後に、ビューポートの寸法のdiv要素が消えるようにしましょう。

これを行うには、ウィンドウオブジェクトの別のメソッドを使用する必要があります 、 setTimeoutと呼ばれます 。このメソッドは、 function()を実行するように設計されています 1回 指定されたミリ秒数。

これは次のように機能します:

setTimeout(functionToExecute, 3000);

1000ミリ秒=1秒。したがって、上記の3000は3秒を意味します。

どの関数を実行しますか? ビューポートディメンションのdiv要素を削除するもの。

そのような関数はまだありません。作成してremoveViewportDimensions()と呼びましょう。 そしてそのコードブロック内{} div要素を削除するように指示しましょう。

次のコードを上記に追加します ウィンドウイベント関数:

function removeViewportDimensions() {
  viewportDimensions.style.display = "none";
}

display プロパティは、方法または if を指定します 要素が表示されます。 'none'に設定する 、非表示にしています。

次に、電話する必要があります 新しいremoveViewportDimensions() 関数、内部から ウィンドウイベントコードブロック。 setTimeout()の使用 以前の形式で、次を追加します:

setTimeout(removeViewportDimensions, 3000);

これで、ウィンドウのサイズ変更イベントがアクティブになるたびに、 setTimeout 3秒のカウントダウンを設定します。言い換えれば、私たちは遅延 removeViewportDimensions()の呼び出し 3秒で。

3秒が経過すると、 removeViewportDimensions() 関数が呼び出され、そのコードが実行されます:

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

これで、div要素のdisplayプロパティが'none'に設定されました。 、および非表示になっています。

しかし問題があります

div要素が削除された直後に、ブラウザウィンドウのサイズをもう一度変更しようとすると、div要素は再び表示されません。 最後だからです プログラムで発生するのは、div要素が displayを取得することです。 プロパティを'none'に設定 。

プログラムのどこにも、div要素を再び表示したいと述べているところはありません。

しかし、なぜ初めて表示されたのですか? デフォルトでは

要素は、いわゆるブロックレベルです。 エレメント。これは、デフォルトの displayを意味します プロパティ値は'block'です —これは目に見える 表示タイプ。

div要素に対して行う最後のことは、その表示値を'none'に設定することです。 。そのため、その値はまだ 2回目にresizeイベントを実行するときは、要素上にあります。ページを更新しない限り。

これは簡単に修正できます。ウィンドウサイズ変更イベントのコードブロック内( setTimeout の上)に以下を追加します !):

viewportDimensions.style.display = "block";

これで、div要素の display プロパティは'block'に設定されています サイズ変更イベントが実行されるたび。ウィンドウのサイズを変更し、div要素が非表示になるのを待ってから、もう一度サイズを変更してみてください。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

素晴らしい、私たちのアプリは動作します!

まあ..ある種。別の問題があります。 ブラウザウィンドウのサイズを長時間(3秒以上)変更しようとすると、div要素がちらつき始めます。まるでライトが絶えずオン/オフされているかのようです。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する このアプリの価値はありません!

これは、カウントダウンタイマーをリセットしていないために発生します。ビューポートのサイズを変更するたびに、windowイベントはその関数コードブロックを可能な限り何度も実行します。したがって、 removeViewportDimensions() 関数はまたです 何度も呼ばれます。

これにより、アプリで多数の重複するコードが実行されます。私たちのdiv要素はdisplay='none'で打たれています プロパティおよび display ='block' 同時にプロパティ。

これにより、div要素が常に表示および非表示になり、ちらつきが発生します。これは最悪だ。この問題を解決するには、タイマーをクリアする方法を学ぶ必要があります。 JavaScriptで動作します。

カウントダウンタイマーのリセット

clearTimeout()を使用して、既存のタイマーをクリアできます 方法。このメソッドは、クリアするように設計されています setTimeoutで設定されたタイマー 方法。それらはパートナーメソッドのようなものです。

既存のタイマーをクリアすることは、まさに私たちが望んでいることです。 setTimeout()のみを実行します タイマー1回 サイズ変更イベントごと。

clearTimeout()を実行できると思われるかもしれません setTimeout()で このように:

clearTimeout(setTimeout);

しかし、それはうまくいきません。 clearTimeout()メソッドを使用するには、グローバルを使用する必要があります タイムアウトメソッドを作成するときに変数。​​

JavaScriptには、グローバルとローカルの2つのスコープがあります:

  • グローバル変数 関数の外部(グローバルスコープ内)で宣言された変数です。
  • ローカル変数 関数内で宣言された変数です(ローカルスコープ)。

これは、 setTimeout()をクリアしたい場合を意味します 最初にグローバル変数に割り当ててから、 clearTimeout()を呼び出すことができます その変数にリセットします。

グローバル変数を作成して、 resizeTimeoutと呼びましょう。 :

var resizeTimeout;

この変数をJavaScriptファイルの一番上に配置します。

今のところ、それは単なる空の変数です。サイズ変更イベントが最初に開始されるまで、空になります。

console.log(resizeTimeout)を使用しようとした場合 未定義になります 戻ってきた。 undefined false 重要な値型。理由はすぐにわかります。

次に、 setTimeout()を取得します 以前の関数を使用して、 resizeTimeoutに割り当てます。 変数:

resizeTimeout = setTimeout(removeViewportDimensions, 3000);

これで、グローバルな resizeTimeout 変数は、 setTimeoutに関する情報を受け取ります サイズ変更イベントがアクティブになるとすぐに機能します。

これで、 setTimeout()を使用できます ウィンドウサイズ変更イベントが実行されるたび。 clearTimeout()を設定します グローバルなresizeTimeout 変数。このように:

clearTimeout(resizeTimeout);

resizeTimeout =setTimeout()のすぐ上にコードを配置します したがって、次のようになります:

clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(removeViewportDimensions, 3000);

では、サイズ変更イベントを5〜6秒間実行すると、ちらつきがなくなったことがわかります。

混乱していますか? コードで何が起こるかについて話しましょう。

JavaScriptインタープリター(ブラウザーで実行されるエンジン)がコードを読み取り、次のことを行います。

  • 行ごとに実行する
  • 一度に1行
  • 上から下へ

ウィンドウのサイズを変更し続ける限り、コードは上から下に実行され続けます。サイズを少し変更するたびに、新しいウィンドウイベントが発生します。そのため、JavaScriptインタープリターは、コードを1秒間に何度も読み取り、実行します。

ウィンドウイベントの関数がそのコードブロックを実行するたびに、 clearTimeout() 既存のをリセットします resizeTimeoutでのキューのカウントダウン 変数。

最後 コード行に、 setTimeout()を割り当てます 。

したがって、最後に発生するのは常に 1 resizeTimeoutに割り当てられる3秒のカウントダウン 。それ以前に開始されたカウントダウンは、 clearTimeout()によって消去されます。 。

素晴らしい!バージョン1が完了しました。ここで完全なコードを表示できます。バージョン2に移りましょう。ここでは、特にパフォーマンスに焦点を当てます。


ビューポートの寸法[バージョン2]

私たちのアプリは動作しますが、それで十分ですか?その質問に答えるには、2つの重要なことを考慮する必要があります。

  • 知覚されるパフォーマンス:ユーザーエクスペリエンス(UX)。
  • ハードウェアのパフォーマンス(使用法と効率)。

UXの観点から、私たちのアプリは素晴らしいパフォーマンスを発揮すると思います。応答時間が非常に速く、古い画面でも非常によくレンダリングされます(私は数十年のベテランでテストしました)。ビジュアルの最適化(UIデザイン)についてはいつでも議論できます。しかし、純粋な機能に基づいて、私たちのアプリはうまく機能します。

しかし、ハードウェアのパフォーマンスから 視点から見ると、私たちのアプリは本当に 悪い。私たちのアプリは、その技術的要件がいかに控えめであるかと比較して、大量のCPUおよびGPUリソ​​ースを使用しています。

理由がわかりますか? ごみ遣いに慣れていないときに、本能的に考えることではありません。 ウィンドウイベントの。

問題は次のとおりです:

ブラウザウィンドウのサイズを変更するたびに、アプリのウィンドウイベントはその関数を数百回実行しています。 ほんの数秒で!

問題を視覚化する関数をCodePenに配置しました。 1秒間に実行される関数の数に注意してください。また、屋根を吹き抜ける総数をすばやく確認してください:

CodePenの例

これは恐ろしく、まったく不要です!私たちのコードは、本来よりもはるかに多くのリソースを使用しています。

ブラウザイベント中にCPUとGPUがどの程度機能しているかを確認するには、Chromeのタスクマネージャを起動します。

JavaScriptを使用してパフォーマンスの高い「ビューポートディメンションを取得」ミニアプリを作成する

ブラウザウィンドウのサイズを変更してみてください。タスクマネージャー内では、アクティブなブラウザータブの横にCPUとGPUの使用率が返されます。

絶対ハードウェア使用量と相対ハードウェア使用量

ハードウェアの絶対使用量と相対使用量を区別することが重要です。絶対的な(全体的な)ハードウェア使用の観点から、私たちの小さなアプリはそれほど害を及ぼしません。ほとんどのコンピューターは非常に強力なので、これに動揺することはできません。

しかし、相対から 使用法の観点から、私たちのアプリはひどく非効率的です。そしてそれが問題です。パフォーマンスを無視する習慣を身につけたくはありません。パフォーマンスが私たちを悩ませ、お尻に噛み付くために戻ってくるからです。

重いを実行するアプリケーションの操作を開始するとすぐに 機能、ハードウェアの使用は深刻な問題になります。今のようにコードを実行すると、見栄えが悪くなります。

ウィンドウイベントの実行方法

デフォルトでは、標準のウィンドウイベントは、イベントがアクティブである限り、可能な限り多くの関数を実行します。小さな変更があるたびに、新しいウィンドウイベントがトリガーされます。これが、私たちのアプリが現在持っている途方もなく高い実行率の原因です。

関数は1秒間に何回実行されますか?

4ミリ秒ごとから40ミリ秒ごとのいずれかになります。これは、次のような多くの要因によって異なります。

  • CPUとGPU(ハードウェア)はどれくらい強力ですか?
  • どのブラウザを使用していますか?
  • 実行しているソフトウェア(コード)はどのくらい複雑ですか?アニメーションが含まれていますか?
  • 現在、ハードウェアは他に何をしていますか?別のタブで実行されているYouTubeビデオを手に入れましたか?

ハードウェアは、特定の時間に利用可能なリソースを使用して、何かを実行するように要求します。

無料が足りない場合もあります 大量のアプリが同時に実行されているため、リクエストにすぐに対応するためのリソース。

これにより、応答時間が遅くなり、画面の不具合、フリーズなどの問題が発生する可能性があります。

ハードウェアの使用量が増えます。 これが、アプリケーションの現在の状態を修正する必要がある理由です。パフォーマンスを重視しているからです!

注:最新のブラウザでは、最小実行速度は4msです フレームレートの観点からは約250fpsです。これは、MozillaのWebAPIドキュメントによるものです。

ただし、このトピックについては矛盾する情報があります。詳細については、こちらをご覧ください。

関数を「実行する」頻度はどれくらいですか?

理想的な関数の実行率は、コンテキストによって異なります。詳細なアニメーションを使用していますか?または、(アプリで行うように)いくつかの数値を返すような単純なものですか?

コンテキストに関係なく、通常、ウィンドウイベントで関数をできるだけ多く実行することは望ましくありません。それはばかげています。また、無料ではありません。やめなきゃ!

スロットリングと呼ばれるプロセスを使用して、実行頻度を制御できます。 それは次に来るでしょう。

イベントスロットリングで救助!

スロットル機能を使用できます 別の回数を制限する 関数は時間の経過とともに実行されます。例:「この関数は100ミリ秒に1回だけ呼び出す」

ウィンドウのサイズ変更イベントによってトリガーされる基本的なイベントスロットル関数を見てみましょう。その後、スロットルは100ミリ秒ごとに外部関数を呼び出します。

基本的なスロットル機能:

var throttled;
var delay = 100;

function functionToExecute() {
  console.log("Executed!");
}

function throttler() {
  if (!throttled) {
    functionToExecute();
    throttled = true;
    setTimeout(function() {
      throttled = false;
    }, delay);
  }
}

window.addEventListener("resize", throttler);

読みやすくするために、コードの書式設定に空白を追加しました。コードを数回読んで、理解できるかどうかを確認してください。

このCodePenを使用してテストします。 functionToExecute()を呼び出すことがわかります 1秒あたり最大10回(10 x 100 =1000 ms =1秒)。

最大と言います 関数は、設定した速度で常に正確に起動するとは限らないためです。これは、関数の実行時にハードウェアがどれだけビジーであるかによって異なります。コンピューターで他のエネルギー課税アプリを実行していますか?。

スロットルコードで何が起こっているか:

これを初めて理解しなくても心配しないでください。最終的にクリックされるまで、私はこのようなものをいじくり回すのに多くの時間を費やしました。

JavaScriptファイルの一番上で、2つのグローバルを宣言することから始めます。 変数:

var throttled; // Empty variable. Type: undefined (falsy value)

var delay = 100; // Number

注:グローバル 変数は、どこからでもこれらの変数にアクセスできることを意味します。

throttledを使用します throttler()の参照ポイントとして 関数、キューに関数があるかどうかを確認します。

throttler()の前 関数が最初にトリガーされると(サイズ変更イベントによって)、キューで実行する関数はありません。したがって、スロットル 空の変数として開始します。

デフォルトでは、空の変数の値の型は undefinedです。 —これは偽り 値型。これが重要である理由がすぐにわかります。

次に、 delay という変数に数値(100)を割り当てます。 。これは、 ms(ミリ秒)を調整するために使用する値です。 throttler()の実行率 機能。

delayに100msを割り当てます 変数。次に、その変数をスロットルの setTimeout()に渡します。 。その後、スロットルは100ミリ秒ごとまたは1秒あたり10回実行されます—最大で。

私はせいぜいと言います 100msは実行率に上限を設けるからです。ユーザーのハードウェアとソフトウェアによっては、実際には1秒あたり10回未満の関数呼び出しを受け取る場合があります。ただし、ほとんどのコンピューターは1秒間に10回起動できます。

スロットル関数内で、条件付きの ifを設定します ステートメント:

function throttler() {
  if (!throttled) {
    // code to execute
  }
}

条件文は、指定された条件に真の値があるかどうかをチェックします。

記号はnotを意味します 。したがって、 if(!throttled) 次のように変換されます:

「スロットルされた場合は 真の値を持っている場合は、 ifを実行します のコード」。

「しかし、スロットルの場合 します 真実の価値を持っているなら、そこでやめなさい!」

JavaScriptのTrueとFalseの値は何ですか?

JavaScriptには、真実があります および偽り 値。うん、それは彼らが呼ばれているものです。真実は真実である価値です。 Falsyは、falseと見なされる値です(驚きです!)。

JavaScriptには、6つの偽の値があります。

  • 未定義
  • null
  • 0
  • '' (空の文字列)
  • NaN
  • false

In JavaScript, anything that is not one of the above values is considered a truthy value. That’s pretty simple, right?

Back to the throttler

With that quick lesson on true vs. false, go ahead and check if our throttled variable is indeed undefined, and a falsy value type.

We can quickly find out with console.log() by using !! to check our variable:

var throttled;
console.log(throttled); // undefined
console.log(!!throttled); // false value

!! is a double not operation. It’s a quick way to check for truthy and falsy values.

Great, now we have confirmed that throttled is undefined, and a falsy value type. This means that the very first time our throttler() runs, if ’s condition is indeed met.

// I start out as a falsy value
var throttled;

// I’m triggered by the window resize event
function throttler() {
  // I will only run my { code } if throttled is falsy (it is!)
  if (!throttled) {
    // code to execute
  }
}

Which means that we can move onto what happens inside if’s code block.

Inside if’s code block

Once inside the if statement code block, we immediately start the callback to functionToExecute

We also set our global throttled variable to true, so it’s no longer undefined (no longer a false value). This stops any future calls to functionToExecute()

if (!throttled) {
  // Run callback
  functionToExecute();
  // Set global throttled variable to true
  throttled = true;

  // ...
}

But then right below, we use setTimeout to reset the the throttled value back to a falsy value, after the 100ms delay:

function throttler() {
  if (!throttled) {
    // Run callback
    functionToExecute();
    // Set global throttled variable to true
    throttled = true;

    setTimeout(function() {
      // Set throttled back to false after delay
      throttled = false;
    }, delay);
  }
}

So every time the window resize event is running, it triggers the throttler() , which will call functionToExecute every 100ms!

Throttling is power

It’s easier to understand how powerful throttling is if you look at two opposite extremes. Try the following in the throttler function on CodePen:

  • Swap 100 out with 500 and resize your window. Notice how infrequent the functionToExecute() is called (twice per second).
  • Then try to swap out 500 with 16 and resize the window. Now functionToExecute() is bombarded with calls (up to 60 calls per second).

That’s how throttling works. We use it to limit the number of times a function can be called over time. It’s a very easy way to avoid wasting hardware resources. The hard part is finding the “optimal” execution rate for a given function, as no project is the same. More about that later.

Adding the throttler to our project

To apply the throttler function to our own project, we’ll need to do a bit of refactoring to the old code first. Refactoring is when we improve the structure of a program but don’t change the overall functionality.

In other words:we take something that already works, and makes it easier to use and understand.

We no longer want the window resize event to directly execute the function that returns width and height. Instead, we want our throttler function to regulate when and how often the code executes.

Fortunately, the change is simple. We just need to declare a named function and then put all code from the anonymous function inside that named function.

Let’s call the new function getViewportDimensions()

function getViewportDimensions() {
  var width = window.innerWidth;
  var height = window.innerHeight;

  viewportDimensions.textContent = width + "px" + " x " + height + "px";
  viewportDimensions.style.display = "block";

  clearTimeout(resizeTimeout);
  resizeTimeout = setTimeout(removeViewportDimensions, 3000);
}

Now let’s take the same throttler function from earlier, and replace the functionToExecute() with getViewportDimensions()

function throttler() {
  if (!throttled) {
    // Callback: the function we want to throttle
    getViewportDimensions();

    throttled = true;

    setTimeout(function() {
      throttled = false;
    }, delay);
  }
}

And finally we add the window resize event listener:

window.addEventListener("resize", throttler);

That’s it, all the hard work is done! Before we wrap up, let’s check our app’s performance, and see if we need to tweak anything.

Hardware Performance vs. Perceived Performance

I don’t know about you, but when I resize my browser window, the width and height numbers are rendering a bit laggy to my screen. It’s not as smooth as it was before we added the throttler.

But that’s not surprising. Before we added the throttler, our code’s execution rate was absurdly high. Now it’s firing around 10 times per second. That’s why it’s a bit laggy now.

There’s no doubt that our app is very performant, from a hardware usage perspective. Our hardware hardly does any work, so it absolutely loves us right now. Which is good.

But what about the perceived performance, from the User Experience point of view? Do our users love us too?

Our rendering should be smoother. Our function execution rate is currently capped at 10 times per second. Let’s increase it. But how much?

We can make it easier to make that decision if we first take a look at the relationship between time and frame rate.

Time vs. Frame Rate

Frame rate is also known as FPS (Frames Per Second). It refers to the number of individual frames displayed per second.

In general, the higher fps the smoother the rendering will be. Video games often need 60fps or more to render smoothly. Most movies and tv series run smoothly at 24-30fps. The more fast-paced action a video or graphic has, the more FPS it needs to render smooth.

For some types of graphics, you can go as low as 15fps and still get a smooth render. But you should rarely go below 15fps because then the perceived performance will start to look noticeably slower.

To find your desired FPS in ms, you divide your target fps with 1000, e.g. 1000/15(fps) =66ms.

Take a look at this FPS to millisecond table:

var 2fps  = 1000/2; // 500ms
var 10fps = 1000/10; // 100ms
var 15fps = 1000/15; // 66ms
var 24fps = 1000/24; // 42ms
var 30fps = 1000/30; // 33ms
var 60fps = 1000/60; // 16ms

Do you recognize something? Our app is currently executing every 100ms, or in frame rate terms:10 frames per second.

Remember, I just said that anything below 15fps will usually appear slow? That could explain why current app’s rendering feels a bit off. There are not enough frames per second to render it smooth. It doesn’t feel instant.

Let’s do some testing

I’ll guarantee that if we crank our Viewport Dimensions feature up to run at 15fps (66ms), it will look significantly smoother than at the current 10fps (100ms).

And it won’t cost too much extra CPU power.

We only need it to be smooth enough.

Like I said earlier, testing opposite extremes is a good way to find out what not する。 Then the question becomes where between the two extremes does your project fit?

Try testing the following frame rates:5fps (500ms), 15fps (66ms), and 60fps (16ms) on your Viewport Dimensions app and see what happens.

What do you think?

5fps looks horrible. It looks broken. That would never work. Our hardware would love it, but our users will hate it!

15fps looks good to me. I wouldn't say that this frame rate is 100% smooth, but it’s clearly better than 10fps.

It’s also important to remember that if your eyes are trained to look for small details, it’s not comparable to the average user’s experience. Most people will consider 15fps smooth, for this type of graphic.

60fps is super smooth — not surprisingly. But honestly, it’s not worth massively extra hardware usage.

I’m going to settle at 15fps for my app.

Why 15 FPS?

The reason I decided on 15fps / 66ms, is because that frame rate is high enough to be perceived as smooth (for most people).

Most software, computers, and displays (screens) can render at 15fps without problems. Even most small, handheld devices can handle 15fps without issue.

The irony of high frame rates is that while logic tells us that more frames per second =smoother, it can also have the opposite effect.

If you try to force a frame rate or refresh rate that your user’s hardware and software can’t handle, the result is often:lagging.

Refresh rate :is how many times your display can redraw your screen. A refresh rate of 45Hz means that your display can redraw it’s entire screen 45 times in 1 second.

Now if your CPU &GPU can generate a frame rate of 60fps, but your display’s refresh rate is only 45Hz, then you have a mismatch. This often causes unpredictable results.

We developers and designers can easily get out of touch with reality. Our development machines are usually more powerful than the average person’s computer.

This is why we need to do solid research and test our assumptions before we push products on the market.

So 15fps is a happy medium that will also work for people who don’t have powerful machines.

Using 15fps will also save us at least 75% of the energy our hardware used before we added the throttler.

Anything below 15fps will usually start to look slow and laggy. It becomes really obvious once you get to around 10fps, which is why our initial frame rate wasn’t good enough.

Here’s an insightful video on the topic of response times which supports my argument for not going below 15fps (on most things).

Context &the Minimum Effective Dose

How much of a perceived difference is there from 15 to 30fps? If you test it out on the app we just built, you’ll be surprised.

You probably won’t be to notice any significant difference. Not a deal-breaking 違い。 But the price you pay for hardware usage is double up!

High fps costs a lot of hardware power. So why use more than necessary? There’s always a point of diminishing returns. That’s where the Minimum Effective Dose (MED) comes in. You only need enough, to get the desired effect, no more, no less.

Of course, it always depends on the context. Are we talking about an explosive first-person shooter video game or a simple pixel counter like the one we’ve built? Context is key!

A Finishing Touch

All the hard work is done. For good measure, let’s wrap all our code inside an IIFE ((function () {...})(); ) and initialize use strict mode inside:

(function() {
  "use strict";

  // Put all your code below

})();

IIFE (Immediately-Invoked Function Expression), keeps all your code inside a local scope.

If we don’t wrap our code like this, we risk “polluting the global namespace”. This is a fancy way of saying that we risk causing conflicts with other code, outside of our app.

use strict; is also used to prevent conflicts with 3rd party software that don’t follow strict coding rules.

We’re done!

Here is all the code we’ve written. I've added some comments for clarification and some extra white space for readability:

Finished project code:

(function() {
  "use strict";

  // throttled value before window event starts
  var throttled;

  // Delay function calls to 66ms (frame rate: 15fps)
  var delay = 66;

  // Declare empty variable for later use
  var resizeTimeout;

  // Grab body element
  var body = document.querySelector("body");

  // Create element
  var viewportDimensions = document.createElement("div");

  // Style element
  viewportDimensions.style.position = "fixed";
  viewportDimensions.style.right = 0;
  viewportDimensions.style.top = 0;
  viewportDimensions.style.padding = "16px";
  viewportDimensions.style.zIndex = 3;
  viewportDimensions.style.fontSize = "22px";

  // Add div element inside body element
  body.appendChild(viewportDimensions);

  // window.resize callback function
  function getViewportDimensions() {
    var width = window.innerWidth;
    var height = window.innerHeight;

    viewportDimensions.textContent = width + "px" + " x " + height + "px";
    viewportDimensions.style.display = "block";

    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(removeViewportDimensions, 3000);
  }

  // Called from getViewportDimensions()
  function removeViewportDimensions() {
    viewportDimensions.style.display = "none";
  }

  function throttler() {
    // Only run code if’s block if we’re not throttled
    if (!throttled) {
      // Callback: the function we want to throttle
      getViewportDimensions();
      // We're currently throttled!
      throttled = true;
      // Reset throttled variable back to false after delay
      setTimeout(function() {
        throttled = false;
      }, delay);
    }
  }

  // Listen to resize event, and run throttler()
  window.addEventListener("resize", throttler);

  // End of IFFE wrapper
})();

Here’s a CodePen you can play with.

How to use your app on any project

Include a script tag at the bottom of your HTML document, just above your closing body tag ( ) and add the path to your js file, like this:

<script src="/js/get-viewport-dimensions.js"></script>

Browser Compatibility

Our app is compatible with all modern browsers, and from Internet Explorer 9 and up.

Advanced throttling

What we learned in this tutorial is a great precursor for some the more powerful performance tools on the market.

If you need to boost performance on more complex projects than the one we built, check out the Lodash JavaScript library. Lodash has a lot of performance features and is very popular among developers. You can also learn a lot from digging through the library’s code.

Resources

  • Mozilla’s Resize Event docs
  • Mozilla’s Frame Rate docs
  • Video on Response Times
  • Frame Rate vs Refresh Rate
  • Why 66ms when using setTimeout

  1. 引数付きのJavaScriptcall()メソッド。

    JavaScriptのcall()関数を使用すると、異なるオブジェクトから同じメソッドを使用できます。ここでは、パラメータが個別に渡されます。 以下は、JavaScript関数call()のコードです- 例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0

  2. 例を使用したJavaScriptでの継承

    JavaScriptは、プロトタイプに基づくオブジェクトベースの言語です。継承は、プロトタイプオブジェクトを使用してJavaScriptで実装されます。 以下は、JavaScriptで継承を実装するためのコードです- 例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-sc