摘要:基礎防抖我們現在寫一個最基礎的防抖處理標記事件也做如下改寫現在試一下,我們會發現只有我們停止滾動秒鐘的時候,控制臺才會打印出一行隨機數。
為何要防抖和節流
有時候會在項目開發中頻繁地觸發一些事件,如 resize、 scroll、 keyup、 keydown等,或者諸如輸入框的實時搜索功能,我們知道如果事件處理函數無限制調用,會大大加重瀏覽器的工作量,有可能導致頁面卡頓影響體驗;后臺接口的頻繁調用,不僅會影響客戶端體驗,還會大大增加服務器的負擔。而如果對這些調用函數增加一個限制,讓其減少調用頻率,豈不美哉?
針對這個問題,一般有兩個方案:
防抖 (Debounce)
節流 (Throttle)
我對函數防抖的定義:當函數被連續調用時,該函數并不執行,只有當其全部停止調用超過一定時間后才執行1次。
一個被經常提起的例子:
上電梯的時候,大家陸陸續續進來,電梯的門不會關上,只有當一段時間都沒有人上來,電梯才會關門。
Talk is cheap,我們直接 show code 吧。
先做基本的準備(篇幅原因,HTML部分省略):
let container = document.getElementById("container"); // 事件處理函數 function handle(e) { onsole.log(Math.random()); } // 添加滾動事件 container.addEventListener("scroll", handle);
我們發現,每滾動一下,控制臺就會打印出一行隨機數。
基礎防抖我們現在寫一個最基礎的防抖處理:
function debounce(func, wait) { var timeout;//標記 return function() { clearTimeout(timeout); timeout = setTimeout(func, wait); } }
事件也做如下改寫:
container.addEventListener("scroll", debounce(handle, 1000));
現在試一下, 我們會發現只有我們停止滾動1秒鐘的時候,控制臺才會打印出一行隨機數。
標準防抖以上基礎版本會有兩個問題,請看如下代碼:
// 處理函數 function handle(e) { console.log(this); //輸出Window對象 console.log(e); //undefined }
沒錯,當我們不使用防抖處理時,handle()函數的this指向調用此函數的container,而在外層使用防抖處理后,this的指向會變成Window。
其次,我們也要獲取到事件對象event。
所以我們要對防抖函數做以下改寫:
function debounce(fn, wait) { let timeout; return function() { clearTimeout(timeout); timeout = setTimeout(()=>{ fn.apply(this,arguments)//使用apply改變this指向 }, wait); } }
當然了,如果使用箭頭函數便可以省去外層聲明。
先觸發式防抖以上的情況都是只有當連續觸發停止后才執行,那如果我們想讓事件第一次觸發就執行,后面的連續觸發都不執行,直到停止觸發一段時間才可以再次觸發(比如防止頻繁點擊),該如何處理呢?
那么可以利用同樣的原理,稍作修改即可:
function debounce(fn, wait) { let timeout; return function(){ let arg = arguments; let that = this; clearTimeout(timeout); !timeout && fn.apply(that,arg) timeout = setTimeout(function(){ timeout = null; }, wait); } }節流 (Throttle)
顧名思義,節流就是節約流量,將連續觸發的事件稀釋成預設評率。
比如每間隔1秒執行一次函數,無論這期間觸發多少次事件。
這有點像公交車, 無論在站點等車的人多不多,公交車只會按時來一班,不會來一個人就來一輛公交車。
標準節流function throttle(fn, wait) { let timeout; return function () { if (!timeout) { timeout = setTimeout(() => { timeout = null; fn.apply(this, arguments) }, wait) } } }
用滾動事件來描述節流,其實是一個非常典型的場景,比如需要用滾動事件判斷是否加載更多等。
先觸發式節流和防抖函數類似,以上的情況是先等待后觸發,如果我們想讓事件先觸發后等待,該如何處理呢?網上大部分文章都告訴你用時間戳的方式去實現,其實只要像防抖一樣稍作修改即可實現。
function throttle(fn, wait) { let timeout; return function () { if (!timeout) { fn.apply(this, arguments) timeout = setTimeout(() => { timeout = null; }, wait) } } }
這樣,我們就會發現第一次觸發函數就會立即生效。
總結關于防抖與節流,lodash、underscore等工具庫都有完善的實現可以直接用,本沒有必要造輪子。本文的目的僅僅是為了將其主要思想和實現思路展現出來。更重要的,知道防抖和節流的本質后,就知道在何時使用防抖或者節流,何時先觸發或后觸發。無論需求如何改變,都可以靈活的運用。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104789.html
摘要:函數防抖和節流,都是控制事件觸發頻率的方法。封裝一個函數,讓持續觸發的事件監聽是我們封裝的這個函數,將目標函數作為回調傳進去,等待一段時間過后執行目標函數第二點實現了,再看第一點持續觸發不執行。 曾經面試時候被問到過這個,年少的我一臉無知。。。 后來工作中遇到了一個場景:輸入名稱的同時去服務器校驗名稱是否重復,但發現之前的代碼竟然都沒做限制,輸入一次發一次請求。簡直忍不了,就在項目的u...
摘要:關于防抖與節流的應用和解釋自行查找資料。修改如果有定時器就清除如果時間滿足就讓他不滿足總之除了第一次就只讓其中一個執行一開始執行一次時間戳,最后停止在執行一次。 這一篇文章我想寫一下防抖與節流,因為我自己不是很理解而且說實話,以前知道,但是老忘,雖然概念還有一些簡單的寫法會,但還是缺乏練習和深刻的理解。 showImg(https://segmentfault.com/img/remo...
摘要:若時間差大于間隔時間,則立刻執行一次函數。不同點函數防抖,在一段連續操作結束后,處理回調,利用和實現。函數防抖關注一定時間連續觸發的事件只在最后執行一次,而函數節流側重于一段時間內只執行一次。 原博客地址,歡迎star 函數防抖和節流 函數防抖和函數節流:優化高頻率執行js代碼的一種手段,js中的一些事件如瀏覽器的resize、scroll,鼠標的mousemove、mouseover...
摘要:對象是無法通過這種方式深拷貝。這就是函數防抖和節流要做的事情。函數防抖當觸發頻率過高時函數基本停止執行而函數節流則是按照一定的頻率執行事件。 對象的深淺拷貝 對象的深拷貝與淺拷貝的區別: 淺拷貝:僅僅復制對象的引用, 而不是對象本身。 深拷貝:把復制的對象所引用的全部對象都復制一遍 淺拷貝的實現: var obj = { age : 18, person : { ...
摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...
閱讀 2386·2021-09-22 16:01
閱讀 3153·2021-09-22 15:41
閱讀 1171·2021-08-30 09:48
閱讀 490·2019-08-30 15:52
閱讀 3324·2019-08-30 13:57
閱讀 1713·2019-08-30 13:55
閱讀 3649·2019-08-30 11:25
閱讀 757·2019-08-29 17:25