防抖和節流

窗口的resize、scroll、輸入框內容校驗等操做時,若是這些操做處理函數是較爲複雜或頁面頻繁重渲染等操做時,在這種狀況下若是事件觸發的頻率無限制,會加劇瀏覽器的負擔,致使用戶體驗很是糟糕。此時咱們能夠採用debounce(防抖)和throttle(節流)的方式來減小觸發的頻率,同時又不影響實際效果。瀏覽器

防抖

在事件被觸發n秒以後執行,若是在此期間再次觸發事件,則從新開始計時。

咱們模擬輸入表單數據,自動獲取後臺數據,聯想搜索,反饋回前臺。監聽keyup事件,若是每次輸入一個字符,就發送一次請求,那麼將在極短的時間發送很是屢次請求,後臺服務器不堪重負!服務器

// 監聽input值 模糊搜索 防止一直搜索
<input id="phone" type="text"/>
// 須要觸發的函數
function debounce(d){
    console.log("聯想搜索phoneNumber:" + d)
}
let inp = document.querySelector("#phone");
// 輸入觸發的事件
function getPhone(fn,delay){
    let timer;
    // 使用閉包,保證每次使用的定時器是同一個
    return (d)=>{
        clearTimeout(timer);
        timer = setTimeout(()=>{
            fn(d);
            // 結束以後清除定時器
            clearTimeout(timer);
        },delay)
    }
}

let getPhoneDebounce = getPhone(debounce,1000);

inp.addEventListener('keyup',(e)=>{
    getPhoneDebounce(e.target.value);
})
當即執行版的意思是觸發事件後函數會當即執行,而後 n 秒內不觸發事件才能繼續執行函數的效果。
/**
 * @param func 函數
 * @param wait 延遲執行毫秒數
 * @param immediate true 表當即執行,false 表非當即執行
 */
function debounce(func,wait,immediate) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

節流

若是持續觸發一個事件,則在必定的時間內只執行一次事件。

咱們模擬射擊,首先第一次點擊射擊的時候,打出一發子彈,當以極短的時間再次點擊射擊的時候,因爲須要‘冷卻’——也就是節流,再次點擊無效,當冷卻時間過了以後,再次點擊射擊,則繼續下一次射擊
準備工具:一個射擊的函數shot, 一個判斷射擊間隔是否結束的函數nextShot,一個觸發射擊的按鈕,判斷射擊是否結束的定時器timer
基本思路:第一次點擊按鈕的時候,觸發shot,當繼續點擊的時候,射擊無效,只有過了定時器設置的時間才能夠繼續射擊。閉包

// 模擬射擊
<button id="shot">射擊</button>
function shot(){
    console.log('射擊')
}
let btn = document.querySelector('#shot');
function nextShot(fn,delay){
    let timer;
    // 閉包原理同上
    return ()=>{
        // 定時器存在,沒法射擊
        if(timer){
            console.log('禁止射擊');
        }else{  // 定時器不存在,射擊,並設置定時器
            fn();
            timer = setTimeout(()=>{
                // 定時器結束,能夠射擊
                clearTimeout(timer);
                timer = null;
            },delay)
        }
    }
}
let start = nextShot(shot,20);
btn.addEventListener('click',()=>{
    start();
})

參考文章來源:

相關文章
相關標籤/搜索