性能一直是前端老生常談的一個話題,其中有一個性能問題就是咱們會頻繁的觸發一些事件,例如mousemove、scroll、resize等,雖然瀏覽器已經對這些事件的觸發作了一些優化,可是若是在很短的時間內頻繁的觸發仍然會影響性能,這個時候就須要今天的主角:防抖和節流,利用它們來進行優化,提升性能。前端
防抖就是將屢次高頻操做優化爲只在最後一次執行(某個函數在某段時間內,不管觸發了多少次回調,都只執行最後一次)。一般的使用場景是:用戶輸入,只需在輸入完成後作一次輸入校驗便可。瀏覽器
防抖是將屢次操做合併爲一次操做完成,其原理就是維護一個計時器,在規定的時間後觸發函數,可是在該規定時間內再次觸發的話就會取消以前的定時器而從新設置,從而保證了只有最後一次操做可以被觸發。其實現步驟以下所示:閉包
function debounce(fn, wait, immediate) { let timer = null; return function (...args) { // 當即執行的功能(timer爲空表示首次觸發) if (immediate && !timer) { fn.apply(this, args); } // 有新的觸發,則把定時器清空 timer && clearTimeout(timer); // 從新計時 timer = setTimeout(() => { fn.apply(this, args); }, wait); } } 複製代碼
觀察效果圖能夠驗證上述的理論知識:app
節流就是每隔一段時間後執行一次,也就是下降頻率,將高頻操做優化成低頻操做。一般使用場景:滾動條事件、resize事件、動畫等,一般每隔100-500ms執行一次便可。ide
節流函數的實現方式有兩種:定時器版本、時間戳版本,這二者各有千秋,下面來簡要實現一下。函數
21.2.2.1 定時器版本性能
定時器版本的節流函數其重點是利用閉包保存timer變量,具備兩個特色:優化
// 定時器版本 function throttle(fn, wait) { let timer = null; return function(...args) { if (!timer) { timer = setTimeout(() => { fn.apply(this, args); timer = null; }, wait) } } } 複製代碼
21.2.2.2 時間戳版本動畫
時間戳版本的節流函數重點是利用閉包保存上一次的時間previous,具備兩個特色:this
// 時間戳版本 function throttle(fn, wait) { // 上一次執行時間 let previous = 0; return function(...args) { // 當前時間 let now = +new Date(); if (now - previous > wait) { previous = now; fn.apply(this, args); } } } 複製代碼
觀察效果圖能夠驗證上述的理論知識: