JSイベントでのブレ防止debounceとスロットルthrottleおよびrequestAnimationFrame


ブラウザのイベントには、resize、scroll、keydown、keyup、keypress、mousemoveなどがあります.これらのイベントのトリガ頻度が頻繁すぎると、これらのイベントにバインドされたコールバック関数が呼び出され続けます.このようにブラウザの目的は情報の一貫性を保証することであり、私たちにとって資源の浪費である.debounceの役割は,ユーザ動作が停止した後にxmsを遅延させてコールバックを実行することである.throttleの役割は、ユーザの動作時に一定時間(例えば200 ms)おきにコールバックを実行しないことである.彼ら2つの共通点は、複数回のコールバックのトリガを1回の実行に統合することです.これにより、頻繁なイベントコールバック操作が大幅に回避されます.本質はイベントコールバック関数をdebounceまたはthrottleでパッケージすることであり、イベントトリガの頻度は変化しないが、カスタマイズしたコールバック関数の実行頻度は低くなっている.この処理はDOM操作に基づく非常に大きなオーバーヘッドである.だから、もしあなたのコールバック関数がjsのデータを処理するだけであれば、ジッタを防ぐ必要はありません.節流処理と同じです.

debounce実装

function debounce(fn,delay){

    var delay=delay||200;
    var timer;
    return function(){
        var th=this;
        var args=arguments;
        if (timer) {
            clearTimeout(timer);
        }
        timer=setTimeout(function () {
                timer=null;
                fn.apply(th,args);
        }, delay);
    };
}
  1

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<style type="text/css">
    #dom{
        width: 200px; height: 200px; background: red
    }
style>
<body>
    <div id="dom">div>
body>
<script type="text/javascript">
document.getElementById('dom').addEventListener("mousemove",debounce(function(){
    console.log(this)
}));
script>
html>
  2

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Documenttitle>
head>
<body>
    <div class="keycont"><input type="text" id="keybtn"/>
    div>
    <div style="position:relative">
        <div class="keysend" id="keyinfo">div>
    div>
body>
<script type="text/javascript">
    var info=document.getElementById("keyinfo");
    var btn=document.getElementById("keybtn");
    btn.addEventListener("keydown",debounce(function(){
        var div=document.createElement("div");
        var str=new Date();
        div.innerText=str
        info.appendChild(div);
    },500));
script>
html>

throttle実装

function throttle(fn,interval){
    var last;
    var timer;
    var interval=interval||200;
    return function(){
        var th=this;
        var args=arguments;
        var now=+new Date();
        if(last&&now-lastfunction(){
                last=now;
                fn.apply(th,args);
            },interval);
        }else{
            last=now;
            fn.apply(th,args);
        }
    }
}
window.addEventListener('scroll', throttle(function  () {
   console.log(11111) 
}));

使い方はdebounceと同じです.コードロジックも似ています.トリガ時に間隔時間interval msを超えると実行されます.そうでなければ実行しません.if判定におけるsettimeoutは、最後のイベントがトリガーされた後に呼び出されることを保証するため、実行間隔時間に達しないたびにtimerをクリアし、timerを再起動する.で指定します.コードロジックも簡単で、言うまでもなく、賢いあなたが見ればわかると信じています.
このthrottleスロットルの機能は,一定の間隔時間でコールバック関数を実行することであり,最も一般的な用途はresize,scrollイベントで処理することである.

requestAnimationFrame


上述のジッタとスロットルの実現方法はいずれもタイマsettimoutを利用しているが、ページが高バージョンのブラウザと互換性があるか、モバイル端末に適用するか、ページが高精度の効果を追求する必要がある場合は、ブラウザのオリジナルの方法requestAnimationFrame windowを使用することができる.requestAnimationFrame()この方法は、ページを再描画する前に、ブラウザに指定した関数を呼び出すように通知するために使用されます.このメソッドでは、再描画前に呼び出される関数をパラメータとして受け入れます.Webアニメーションの作成によく使用され、ページのフレームリフレッシュレンダリングを正確に制御し、アニメーションの効果をよりスムーズにするために使用されます.もちろん、アニメーションの作成に限らず、その特性を利用してタイマーと見なすことができます.(もちろんタイマーではありません)
通常、requestAnimationFrameが呼び出される頻度は毎秒60回、すなわち1000/60であり、トリガ頻度は約16.7 msである.(複雑な動作を実行すると、60 fpsの周波数を維持できないことが分かった場合、フレーム数の安定性を維持するために30 fpsに周波数を低下させる.)
簡単に言えば、requestAnimationFrameを使用してスクロールイベントをトリガーします.
throttle(fn,16.7)

まとめ


debounceはkeydownイベントでユーザー名を検証するのに最適です.throttleはresizeでレイアウトを変更し、onscrollをスクロールするときに使用されます.requestAnimationFrameは調整性が非常に悪い.ただし、throttle(func,16.7)よりも複雑なシーンで使用する場合、requestAnimationFrameの方が効果的で、パフォーマンスが優れている可能性があります.