今天在改一個看似很簡單之前也常常遇到的一個bug發現了不少問題。
實際結果確定沒有想象的那麼簡單。因此我想總結一下:保證下次不會踩坑。
---
業務場景是點擊一個按鈕,會產生一個彈框。重複快速的點擊屢次,會產生多個彈框。
那麼這個問題該怎麼解決呢?javascript
1. 函數防抖節流
這兩個東西我不知道看過了多少文檔,可到如今掌握的仍是不夠好。
因此今天我想趁熱打鐵一波,把他們不折不扣給搞明白!java
防抖:什麼是防抖呢? 就是好比你規定一段延時 時間,在這段時間內你持續觸發這個事件,事件處理函數纔會執行一次,若是設定的時間到來以前,你又觸發了一次事件,就從新開始延時。 來個圖更加形象!小程序
//接着確定就是實現防抖的代碼了 //防抖 function debounce(fn,wait) { var timeout = null; return function() { if(timeout !== null) clearTimeout(timeout) timeout = setTimeout(fn,wait) } } //處理函數 function handle() { console.log(Math.random()) } //滾動事件 window.addEventListener('scroll',debounce(handle,1000))
當持續觸發scroll事件時,事件處理函數handle只在中止滾動1000毫秒以後纔會調用一次,也就是說在持續觸發scroll事件的過程當中,事件處理函數handle一直沒有執行。
節流:那麼什麼是節流呢?認識了防抖以後必定不要混淆了節流的概念,我以前就是犯這個錯誤。
言歸正傳,節流就是當你持續觸發事件時,保證一段時間內只調用一次事件的處理函數,通俗點說就好比咱們水龍頭放水,閥門一打開,水嘩嘩的往下流,秉着勤儉節約的優良傳統美德,咱們要把水龍頭關小點,最好是如咱們心意按照必定規律在某個時間間隔內一滴一滴的往下滴。以下圖,持續觸發scroll事件時,並不當即執行handle函數,每隔1000毫秒纔會執行一次handle函數。微信小程序
函數節流主要有兩種實現方法:時間戳和定時器。接下來分別用兩種方法實現throttle~微信
//節流函數(時間戳) function throttle(fn, delay) { //記錄第一次執行時的時間 var prev = Date.now() return function() { var contxt = this var args = arguments var now = Date.now() //若是當前時間減去上一次執行的時間大於等於延時時間 if(now -prev >= delay) { //執行 fn.apply(contxt, args) //執行後的時間 prev = Date.now() } } } //處理函數 function handle() { console.log(Math.random()) } //滾動事件 window.addEventListener('scroll',throttle(handle,1000)) ``` ```javascript //節流函數(定時器) function throttle(fn, delay) { var timer = null return function() { var contxt = this var args = arguments //若是定時器不存在 if(!timer) { timer = setTimeout(function(){ fn.apply(contxt,args) timer = null },delay) } } } //處理函數 function handle() { console.log(Math.random()) } //滾動事件 window.addEventListener('scroll',throttle(handle,1000))
當觸發事件的時候,咱們設置一個定時器,再次觸發事件的時候,若是定時器存在,就不執行,直到delay時間後,定時器執行執行函數,而且清空定時器,這樣就能夠設置下個定時器。當第一次觸發事件時,不會當即執行函數,而是在delay秒後才執行。然後再怎麼頻繁觸發事件,也都是每delay時間才執行一次。當最後一次中止觸發後,因爲定時器的delay延遲,可能還會執行一次函數。
節流中用時間戳或定時器都是能夠的。更精確地,能夠用時間戳+定時器,當第一次觸發事件時立刻執行事件處理函數,最後一次觸發事件後也還會執行一次事件處理函數。app
// 節流throttle代碼(時間戳+定時器): var throttle = function(func, delay) { var timer = null; var startTime = Date.now(); return function() { var curTime = Date.now(); var remaining = delay - (curTime - startTime); var context = this; var args = arguments; clearTimeout(timer); if (remaining <= 0) { func.apply(context, args); startTime = Date.now(); } else { timer = setTimeout(func, remaining); } } } function handle() { console.log(Math.random()); } window.addEventListener('scroll', throttle(handle, 1000));
函數防抖:將幾回操做合併爲一此操做進行。原理是維護一個計時器,規定在delay時間後觸發函數,可是在delay時間內再次觸發的話,就會取消以前的計時器而從新設置。這樣一來,只有最後一次操做能被觸發。dom
函數節流:使得必定時間內只觸發一次函數。原理是經過判斷是否到達必定時間來觸發函數。函數
區別: 函數節流無論事件觸發有多頻繁,都會保證在規定時間內必定會執行一次真正的事件處理函數,而函數防抖只是在最後一次事件後才觸發一次函數。 好比在頁面的無限加載場景下,咱們須要用戶在滾動頁面時,每隔一段時間發一次 Ajax 請求,而不是在用戶停下滾動頁面操做時纔去請求數據。這樣的場景,就適合用節流技術來實現。this
今天本想用其中一種方法解決我前面提到的業務場景,可萬萬沒想到的是,兩種方法我試了,都不行,多是微信小程序的機制和PC端不一樣的緣故吧,因此最後 我採用了遮罩層的方法實現。
就是在他第一次點擊的時候就設置一個遮罩層,不讓他點擊了,不就成功解決了這個問題了麼???spa