適合小白看的前端防抖節(jié)流

防抖 操作時不執(zhí)行 確定不操作了才執(zhí)行,在前端應(yīng)用場景還是比較多的

好比你在一直玩手機(jī)的時候,手機(jī)不會息屏 玩了一分鐘不玩了 就息屏了

原理: 操作(你快動我?。?>關(guān)閉定時器(好了,我要重新數(shù)數(shù)了)=>重新開始計(jì)算器(你再不動我就要息屏了)=>執(zhí)行(手機(jī)息屏了)

如何去實(shí)現(xiàn)這么一個函數(shù)

1.創(chuàng)建一個函數(shù),他接受倆個參數(shù),一個是你想去防抖的函數(shù),一個是你想延時操作的時間

function debounce(fun,delay){

}

2.他返回一個自執(zhí)行函數(shù),并且這個函數(shù)在 delay后執(zhí)行

function debounce(fun,delay){
    return function(){
        setTimeout(()=>{
            fun()
        },delay)
    }
}

此時其實(shí)已經(jīng)實(shí)現(xiàn)了一個延時函數(shù)了,但是需要自執(zhí)行一下,因?yàn)槲覀兎祷氐氖呛瘮?shù)體,可以使用debounce(fun,delay)(),或者return function(){}()加個括弧

function debounce(fun,delay){
    return function(){
        setTimeout(()=>{
            fun()
        },delay)
    }
}

function sleep(){
    console.log(1)
}
debounce(sleep,3000)()

那當(dāng)然這種代碼肯定沒有如下來的簡潔

const sleep = time =>{
  return new Promise(resolve=>setTimeout(resolve,time))
}

3.再來看一遍原理 操作=>關(guān)閉定時器=>重新開始計(jì)算器=>執(zhí)行,那么接下來就是對定時器的操作,我們聲明一個定時器然后并覆蓋

function debounce(fun,delay){
    let timer
    return function(){
        if(timer) clearTimeout(timer)
        timer = setTimeout(()=>{
            fun()
        },delay)
    }
}

那么到這步,其實(shí)已經(jīng)實(shí)現(xiàn)了大多數(shù)的防抖,我們嘗試一下

function watchResize() {
    console.log(1)
}
window.addEventListener('resize', debounces(watchResize, 1000))

在頁面中進(jìn)行窗口改變的時候,當(dāng)你停止改變1s后就會打印1,當(dāng)然這個函數(shù)還有一些優(yōu)化,比如對fn的類型判斷,delay的處理等等,了解基礎(chǔ)原理之后 稍微進(jìn)階一下

<input type="text" id="ipt">

比如我們寫個input,給它綁定一個input事件

ipt.oninput = function(){
    console.log(this.value)
}

OK,此時沒有問題,但是我們想要用戶最后輸入的值,做個防抖

ipt.oninput = debounce(function () { 
    console.log(this.value)
 }, 2000)

此時控制臺你會發(fā)現(xiàn),打印的是undefined,問題就出在this指向問題

ES5: 一個函數(shù)在被調(diào)用時,會自動取得兩個特殊變量:this和arguments。在全局環(huán)境調(diào)用函數(shù)時,this代表window對象;而當(dāng)函數(shù)被作為其他某個對象的方法而調(diào)用時,this就代表那個對象。

簡而言之: ES5的函數(shù)中,this是執(zhí)行時函數(shù)所在的那個對象。

function debounce(fun, delay) {
    console.log(this)  //此處打印的是windows
    let timer
    return function () {
        //此處是執(zhí)行環(huán)境  因?yàn)榉祷氐暮瘮?shù) 在xx環(huán)境下觸發(fā)的  xx就是調(diào)用的對象
        console.log(this)
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fun()
        }, delay)
    }
}

所以我們在定時器的函數(shù)執(zhí)行顯示綁定當(dāng)前的this即可

function debounce(fun, delay) {
    let timer
    return function () {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fun.apply(this)
        }, delay)
    }
}

同理,調(diào)用的時候就不能使用箭頭函數(shù),箭頭函數(shù)不存在this,當(dāng)然你非要用 ,可以這樣用

const co = (obj)=>obj.value
ipt.oninput = debounce(function(){
    console.log(co(this))
},1000)

感覺就挺憨的?。?/p>

節(jié)流,原理差不多,都是操控時間

好比你打游戲的技能冷卻,亦或是你等的公交車,總是多少時間來一趟,如何控制時間有倆種說法,可以通過當(dāng)前時間減去上一次時間,也可以通過設(shè)置的時間去操作,兩種思路都可以

我們先按照防抖的思路寫一個setTimeout版本,老樣子 先返回一個函數(shù),有了前面的基礎(chǔ),現(xiàn)在節(jié)奏快點(diǎn)

function throttle(fn,delay){
    return function(){
        setTimeout(()=>{
            fn.apply(this,arguments)
        },delay)
    }
}

然后我們?nèi)プ鲆幌驴刂?/p>

function throttle(fn, delay) {
    //開啟一個值 默認(rèn)關(guān)閉
    let timer = false
    return function () {
        //如果這個timer是開啟的 那么說明我們在時間范圍之外 那我們不做啥 直接返回
        if (timer) {
            return
        }
        else {
            //開啟這個值
            timer = true
            setTimeout(() => {
                fn.apply(this, arguments)
                //說明下一次可以執(zhí)行了 那你就繼續(xù)false吧
                timer = false
            }, delay)
        }

    }
}

window.addEventListener('resize', throttle(watchresize, 2000))

然后你發(fā)現(xiàn)在一直操作窗口的時候,2s觸發(fā)一次咯

    function throttle(fun, delay) {
        let previous = 0;
        return function () {
            let now = Date.now();
            let args = arguments;
            if (now - previous > delay) {
                func.apply(this, args);
                previous = now;
            }
        }
    }

也可以使用時間戳去控制??! 看完嘗試自己再手寫幾遍就應(yīng)該可以理解了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容