摘要:如果本次定時器沒有被清除,時間到后就會自然執行事件處理函數。綁定去抖后的事件回調函數綁定回調函數的屬性方法,點擊頁面,重置去抖效果異步請求清空上一次事件觸發的定時器重置為從而下一次事件觸發就能立即執行。
一、前言
為什么會有去抖和節流這類工具函數?
在用戶和前端頁面的交互過程中,很多操作的觸發頻率非常高,比如鼠標移動 mousemove 事件, 滾動條滑動 scroll 事件, 輸入框 input 事件, 鍵盤 keyup 事件,瀏覽器窗口 resize 事件。
在以上事件上綁定回調函數,如果回調函數是一些需要大量計算、消耗內存、HTTP 請求、DOM 操作等,那么應用的性能和體驗就會非常的差。
去抖和節流函數的根據思想就是,減少高頻率事件處理函數 handler 的執行頻率(注意是事件處理函數,不是事件回調函數),將多次事件的回調合并成一個回調來執行,從而優化性能。
二、簡單版去抖(debounce)去抖(debounce),也叫防抖,那抖動指的是什么呢?抖動意味著操作的不穩定性,你可以理解成躁動癥,安靜不下來~防抖的含義便是為了防止抖動造成的結果不準確,等到穩定的時候再處理結果。
比如在輸入事件,鼠標移動,滾動條滑動,鍵盤敲擊事件中,等到停止事件觸發,頻率穩定為零后,才開始執行回調函數,也就是所謂的沒有抖動后處理。
個人總結:去抖,就是事件觸發頻率穩定后,才開始執行回調函數, 一連串的事件觸發,但只進行一次事件處理。
頻率就是單位時間觸發的次數,如果單位時間內,事件觸發超過一次,就只執行最后一次,如果單位時間內沒有觸發超過一次,那就正常執行。去抖分為延遲執行和立即執行兩種思路。
看一個簡單版的去抖函數延遲執行實現:
輸入框:
上面代碼中我的注釋已經能夠說明整個去抖的過程,再來啰嗦幾句話~
debounce 函數在主線程順序執行時已經被調用,傳入的參數一個是真正想在事件觸發執行的事件處理函數
另一個參數是事件觸發的間隔時間,間隔時間內再次觸發事件,則重新計時,類似于罰你 5 分鐘內不準說話,時間到后就可以開始說話,如果 5 分鐘內說話了,則再罰你 5 分鐘內不準說話,以此類推~
debounce 函數有一個 timer 內部變量,timer 在返回的執行函數中被訪問,形成了閉包,有關閉包的內容,可以翻看我之前的文章《JavaScript之閉包》
bebounce 函數返回的匿名函數才是 input 事件的回調函數,所以該匿名函數有一個默認參數 event 對象。
同第 4 點,匿名函數是 dom 元素注冊事件的回調函數,所以匿名函數(回調函數)的 this 指向 HTMLInput 元素。
同第 2 點,觸發函數后,如果發現閉包中保存著 timer 變量, timer 變量初始值為 null, 之后觸發定時器后,timer 為當次定時器的 id,id 是一個數字。去抖的過程在于,如果在定時器的間隔時間內觸發了函數,它會把上一次事件觸發時定義的定時器清除,又重新定義一個定時器。如果本次定時器沒有被清除,時間到后就會自然執行事件處理函數。對這個過程有困惑的同學,可以把 timer 變量在 clearTimeout 之前打印出來就明白了。
延時執行了事件處理函數(handler),需要傳遞調用對象和事件對象過去,此處 call 可以和 apply 互換,如果用 apply, 傳遞 arguments 類數組即可。這樣保證了參數的一致性,就像沒被 debounce 處理過一樣。
以上就是去抖函數的基本思想, 可以參考示意圖
下面這張圖是高設 3 里講的節流函數,其實是這一節所說的去抖函數,高設 3 將 timer 變量用傳入的處理函數的屬性代替了而已。
第二節的簡單版去抖函數能滿足大部分只需要觸發一次事件處理的去抖場景:輸入數據查詢事件,下拉滾動條到窗口底部懶加載數據。
但是有一個問題,假如我想輸入框輸入內容時,第一個字輸完就請數據怎么做? 你可以理解為,你可以馬上開始說話,但是說完話后 5 分鐘不能說話,如果 5 分鐘內說話,則接下來再加 5 分鐘不能說話。如果 5 分鐘后沒說話, 那么接下來,你又可以先說話,然后閉嘴 5 分鐘~
所以,引出來了立即執行版的去抖函數。
取消功能實現
輸入框:
上面代碼的注釋,可以解釋整個流程,下面大致說一下:
非立即執行版本和前一節內容一樣,跳過。
timer 初始值為 null, 第一次觸發為立即執行,!timer 為 true, 所以能夠立即調用事件處理函數。
每次事件觸發, 都會把 timer 重新賦值,在間隔時間到之前 timer 為數字 id, !timer 為 false, 所以不能立即執行。如果間隔時間到了,會把當次事件觸發的定時器 id 置為 null, 下一次事件觸發就能立即執行了。
朋友們可以通過觀察 timer 值的變化,思考整個過程,timer 在去抖的過程中充當 flag 的作用,可以用來判斷能否立即執行。
看看效果:
取消函數假如去抖函數的間隔時間為 5 秒鐘,我在這 5 秒鐘內又想立即執行可以怎么做?于是我們給回調函數加個取消函數屬性。
函數也是一個對象,可以像其他一般對象那樣添加方法:
輸入框:
看看效果:
去抖函數的意義在于合并多次事件觸發為一次事件處理,從而降低事件處理函數可能引發的大量重繪重排,http 請求,內存占用和頁面卡頓。
另外,本文有關 this, call, apply,閉包的知識,可以翻看我之前分享的文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99829.html
摘要:專題系列共計篇,主要研究日常開發中一些功能點的實現,比如防抖節流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數組合專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。 JavaScript 專題之從零實現 jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現一個 jQuery 的 ext...
摘要:包是開發中常用的工具包,里面有許多實用的方法,今天分析常用的一個去重方法用法源碼包可以看到,函數這邊只做了一個針對的封裝,所以繼續看源碼 lodash.js包是node開發中常用的js工具包,里面有許多實用的方法,今天分析常用的一個去重方法---uniq 用法 _.uniq([2, 1, 2]) // => [2, 1] 源碼包 // uniq.js i...
閱讀 3237·2021-09-07 10:10
閱讀 3582·2019-08-30 15:44
閱讀 2582·2019-08-30 15:44
閱讀 2998·2019-08-29 15:11
閱讀 2225·2019-08-28 18:26
閱讀 2748·2019-08-26 12:21
閱讀 1116·2019-08-23 16:12
閱讀 3029·2019-08-23 14:57