JS 関数のデバウンスとスロットリングの詳細な分析
1. スロットリングとデバウンスとは何ですか?
倹約。蛇口を締めるだけで水の流れは少なくなりますが、水の流れは止まりません。現実の生活では、水を汲むためにバケツに水を汲む必要がある場合があると想像してください。私たちは、何か他のことをするためにずっとそこに立って待っていたくありません。再び戻ってくるときに、水がバケツにいっぱいになるようにしてください。そうしないと、戻ってくる前に水がいっぱいになり、大量の水を無駄にすることになります。戻ってくるときに水がほぼ満タンになるようにスロットルを下げる必要があります。では、JS にはそのような状況があるのでしょうか? 典型的なシナリオは、画像の遅延読み込みとページの scoll イベントの監視、またはマウスの mousemove イベントの監視です。 Mousemove はマウスが移動するときに使用され、ブラウザによって頻繁にトリガーされるため、対応するイベントが頻繁にトリガーされ (水の流れが速すぎる)、ブラウザーのリソースのオーバーヘッドが大きくなり、中間処理は不要です。このとき、スロットリングする必要があります。ブラウザーが対応するイベントをトリガーするのを防ぐことはできませんが、イベント処理メソッドの実行頻度を減らすことはでき、それによって対応する処理のオーバーヘッドを減らすことができます。
揺れを解消します。私がこの用語に初めて触れたのは、おそらく高校の物理でした。スイッチが実際に閉じる前にジッターが発生する場合がありますが、そのジッターに対応する小さな電球が点滅しても問題はありません。 . この時、また目にダメージを受けると厄介です。このページでも、ユーザーがコンテンツを入力しているときに、入力ボックスの 1 つがバックグラウンドで対応する単語をクエリすると、入力イベントが頻繁にトリガーされ、その後、逆方向にクエリが実行されるとします。リクエストが発生すると、ユーザーの入力が完了するまで前のリクエストは冗長である必要があります。ネットワークが遅く、バックグラウンドから返されるデータが遅いと仮定すると、表示される関連単語は最後のリクエストが返されるまで頻繁に変更される可能性があります。このとき、一定時間内に再度入力するかどうかを監視し、再度入力がない場合は入力が完了したものとみなし、リクエストを送信します。まだ入力中のため、リクエストは送信されません。
デバウンスとスロットルは異なります。スロットルは中間処理関数を制限しますが、周波数を下げるだけですが、デバウンスはすべての中間処理関数を除外し、指定された時間内のタスクのみを実行します。
2. JS実装。
スロットリング:
/** 实现思路: ** 参数需要一个执行的频率,和一个对应的处理函数, ** 内部需要一个lastTime 变量记录上一次执行的时间 **/ function throttle (func, wait) { let lastTime = null // 为了避免每次调用lastTime都被清空,利用js的闭包返回一个function确保不生命全局变量也可以 return function () { let now = new Date() // 如果上次执行的时间和这次触发的时间大于一个执行周期,则执行 if (now - lastTime - wait > 0) { func() lastTime = now } } }
呼び出し方法を見てみましょう:
// 由于闭包的存在,调用会不一样 let throttleRun = throttle(() => { console.log(123) }, 400) window.addEventListener('scroll', throttleRun)
この時点で、ページを狂ったようにスクロールすると、123 が 400 ミリ秒で出力されることがわかります。スロットリングはなく、継続的に出力されます。違いを感じるために待機パラメータを変更できます。
しかし、ここでは、私たちのメソッドがイベントの発生時に this オブジェクトを取得しないことと、このトリガーの時間と最後の実行間隔の時間を判断して決定するという単純かつ粗雑なメソッドであるため、ここでのスロットルメソッドは不完全です。コールバックを実行するかどうか、これにより最後のトリガーが実行できなくなるか、実際にユーザーの出発間隔が非常に短いために実行できず、過失致死が発生するため、メソッドを改善する必要があります。
function throttle (func, wait) { let lastTime = null let timeout return function () { let context = this let now = new Date() // 如果上次执行的时间和这次触发的时间大于一个执行周期,则执行 if (now - lastTime - wait > 0) { // 如果之前有了定时任务则清除 if (timeout) { clearTimeout(timeout) timeout = null } func.apply(context, arguments) lastTime = now } else if (!timeout) { timeout = setTimeout(() => { // 改变执行上下文环境 func.apply(context, arguments) }, wait) } } }
このようにして、私たちのメソッドは比較的完成しており、呼び出しメソッドは以前と同じです。
デバウンス:
デバウンス メソッドはスロットリングと一致しますが、このメソッドはジッターが終了したと判断された後にのみ実行されます。
debounce (func, wait) { let lastTime = null let timeout return function () { let context = this let now = new Date() // 判定不是一次抖动 if (now - lastTime - wait > 0) { setTimeout(() => { func.apply(context, arguments) }, wait) } else { if (timeout) { clearTimeout(timeout) timeout = null } timeout = setTimeout(() => { func.apply(context, arguments) }, wait) } // 注意这里lastTime是上次的触发时间 lastTime = now } }
このとき、先ほどと同じ方法で呼び出してみると、ウィンドウをどれだけスクロールしても、スクロールを止めたときにのみ対応するイベントが実行されることがわかります。
デバウンスとスロットルは多くの成熟した JS によって実装されており、一般的なアイデアは基本的に次のとおりです。
ネチズンの実装メソッドのコードを共有しましょう:
メソッド 1
1. この実装メソッドのアイデアは理解しやすいです: 50 などの間隔を設定します。ミリ秒、〜 この時間がタイマーを設定するためのベースラインとして使用されます。最初のトリガー イベントと 2 番目のトリガー イベントの間の間隔が 50 ミリ秒未満の場合は、このタイマーをクリアして新しいタイマーを設定し、50 ミリ秒になるまで続けます。イベントがトリガーされた後、ミリ秒以内に再トリガーはありません。コードは次のとおりです。
function debounce(method){ clearTimeout(method.timer); method.timer=setTimeout(function(){ method(); },50); }
この設計方法には問題があります。複数回トリガーされるべきイベントが、結局 1 回しか発生しない可能性があります。具体的には、段階的なスクロール イベントの場合、ユーザーのスクロールが速すぎる場合、またはプログラムによって設定された機能のスロットル間隔が長すぎる場合、最後のスクロール イベントが突然のジャンプ イベントとして表示され、中間のプロセスがスロットリングによって中断されます。 。この例は少し誇張されていますが、この方法を使用して調整すると、最終的にプログラムが調整されていない場合よりも「より唐突に」感じられるようになり、ユーザー エクスペリエンスが非常に悪くなります。この欠点を補う設計上のアイデアがあります。
方法 2
2.第二种实现方式的思路与第一种稍有差别:设置一个间隔时间,比如50毫秒,以此时间为基准稳定分隔事件触发情况,也就是说100毫秒内连续触发多次事件,也只会按照50毫秒一次稳定分隔执行。代码如下:
var oldTime=new Date().getTime(); var delay=50; function throttle1(method){ var curTime=new Date().getTime(); if(curTime-oldTime>=delay){ oldTime=curTime; method(); } }
相比于第一种方法,第二种方法也许会比第一种方法执行更多次(有时候意味着更多次请求后台,即更多的流量),但是却很好的解决了第一种方法清除中间过程的缺陷。因此在具体场景应根据情况择优决定使用哪种方法。
对于方法二,我们再提供另一种同样功能的写法:
var timer=undefined,delay=50; function throttle2(method){ if(timer){ return ; } method(); timer=setTimeout(function(){ timer=undefined; },delay); }
以上内容就是JS函数去抖和节流详解,希望能帮助到大家。
相关推荐:
以上がJS 関数のデバウンスとスロットリングの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go 言語は、クロージャとリフレクションという 2 つの動的関数作成テクノロジを提供します。クロージャを使用すると、クロージャ スコープ内の変数にアクセスでき、リフレクションでは FuncOf 関数を使用して新しい関数を作成できます。これらのテクノロジーは、HTTP ルーターのカスタマイズ、高度にカスタマイズ可能なシステムの実装、プラグイン可能なコンポーネントの構築に役立ちます。

C++ 関数の名前付けでは、読みやすさを向上させ、エラーを減らし、リファクタリングを容易にするために、パラメーターの順序を考慮することが重要です。一般的なパラメータの順序規則には、アクション-オブジェクト、オブジェクト-アクション、意味論的な意味、および標準ライブラリへの準拠が含まれます。最適な順序は、関数の目的、パラメーターの種類、潜在的な混乱、および言語規約によって異なります。

効率的で保守しやすい Java 関数を作成するための鍵は、シンプルに保つことです。意味のある名前を付けてください。特殊な状況に対処します。適切な可視性を使用してください。

1. SUM 関数は、列またはセルのグループ内の数値を合計するために使用されます (例: =SUM(A1:J10))。 2. AVERAGE 関数は、列またはセルのグループ内の数値の平均を計算するために使用されます (例: =AVERAGE(A1:A10))。 3. COUNT 関数。列またはセルのグループ内の数値またはテキストの数をカウントするために使用されます。例: =COUNT(A1:A10)。 4. IF 関数。指定された条件に基づいて論理的な判断を行い、結果を返すために使用されます。対応する結果。

C++ 関数のデフォルト パラメーターの利点には、呼び出しの簡素化、可読性の向上、エラーの回避などがあります。欠点は、柔軟性が限られていることと、名前の制限があることです。可変引数パラメーターの利点には、無制限の柔軟性と動的バインディングが含まれます。欠点としては、複雑さの増大、暗黙的な型変換、デバッグの難しさなどが挙げられます。

C++ で参照型を返す関数の利点は次のとおりです。 パフォーマンスの向上: 参照による受け渡しによりオブジェクトのコピーが回避され、メモリと時間が節約されます。直接変更: 呼び出し元は、返された参照オブジェクトを再割り当てせずに直接変更できます。コードの簡素化: 参照渡しによりコードが簡素化され、追加の代入操作は必要ありません。

カスタム PHP 関数と定義済み関数の違いは次のとおりです。 スコープ: カスタム関数はその定義のスコープに限定されますが、事前定義関数はスクリプト全体からアクセスできます。定義方法: カスタム関数は function キーワードを使用して定義されますが、事前定義関数は PHP カーネルによって定義されます。パラメータの受け渡し: カスタム関数はパラメータを受け取りますが、事前定義された関数はパラメータを必要としない場合があります。拡張性: カスタム関数は必要に応じて作成できますが、事前定義された関数は組み込みで変更できません。

C++ の例外処理は、特定のエラー メッセージ、コンテキスト情報を提供し、エラーの種類に基づいてカスタム アクションを実行するカスタム例外クラスを通じて強化できます。 std::Exception から継承した例外クラスを定義して、特定のエラー情報を提供します。カスタム例外をスローするには、throw キーワードを使用します。 try-catch ブロックでdynamic_castを使用して、キャッチされた例外をカスタム例外タイプに変換します。実際の場合、open_file 関数は FileNotFoundException 例外をスローします。例外をキャッチして処理すると、より具体的なエラー メッセージが表示されます。
