陸游有一首《冬夜讀書示子聿》——「古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。」,其中的意思想必你們都能明白,在學習或工做中,不斷的印證着這首詩的內涵。因此,又有了此篇小菊花文章。javascript
在前端開發中,咱們常常會碰到一些會持續觸發的時間,好比 輸入框校驗、resize、scroll、mousemove 等操做時,若是事件觸發的頻率無限制,會家中瀏覽器的負擔,致使用戶體驗很是糟糕。
咱們能夠先看看持續觸發過程當中頻繁執行函數是怎樣的狀況css
<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div> <script> var num = 1; var content = document.getElementById('content'); function count() { content.innerHTML = num++; }; content.onmousemove = count; </script>
在上面代碼中,div 元素綁定了 mousemove 事件,當鼠標在 div(灰色)區域中移動的時候會持續地去觸發該事件致使頻繁執行函數。html
再看一個例子前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>沒有防抖</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = function () { //模擬ajax請求 function ajax(content) { console.log('ajax request ' + content) } let inputNormal = document.getElementById('normal'); inputNormal.addEventListener('keyup', function (e) { ajax(e.target.value) }) } </script> </head> <body> <div> 1.沒有防抖的input: <input type="text" name="normal" id="normal"> </div> </body> </html>
在上面代碼中,會監聽鍵盤輸入事件,只要按下鍵盤,就會觸發此次模擬的ajax請求,不只浪費了資源,並且在實際應用中,用戶也是須要輸入完整字符後,才請求。java
簡單來講就是防止抖動,指觸發事件在 n 秒內函數只能執行一次,若是在 n 秒內又觸發了事件,則會從新計算函數執行時間。
咱們將上面的代碼加入防抖優化一下:ajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>加入防抖</title> <style type="text/css"></style> <script type="text/javascript"> window.onload = function () { //模擬ajax請求 function ajax(content) { console.log('ajax request ' + content) } function debounce(fun, delay) { return function (args) { //獲取函數的做用域和變量 let that = this let _args = args //每次事件被觸發,都會清除當前的timeer,而後重寫設置超時調用 clearTimeout(fun.id) fun.id = setTimeout(function () { fun.call(that, _args) }, delay) } } let inputDebounce = document.getElementById('debounce') let debounceAjax = debounce(ajax, 500) inputDebounce.addEventListener('keyup', function (e) { debounceAjax(e.target.value) }) } </script> </head> <body> <div> 2.加入防抖後的輸入: <input type="text" name="debounce" id="debounce"> </div> </body> </html>
上面代碼加入防抖後,當持續在輸入框裏輸入時,並不會發送請求,只有當在指定時間間隔內沒有再輸入時,纔會發送請求。若是先中止輸入,可是在指定間隔內又輸入,會從新觸發計時。segmentfault
規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,若是在同一個單位時間內某事件被觸發屢次,只有一次能生效。
咱們一樣在上面的需求上進行修改,加入節流函數。瀏覽器
//模擬ajax請求 function ajax(content) { console.log('ajax request ' + content) } function throttle(fun, delay) { let last, deferTimer return function (args) { let that = this; let _args = arguments; let now = +new Date(); if (last && now < last + delay) { clearTimeout(deferTimer); deferTimer = setTimeout(function () { last = now; fun.apply(that, _args); }, delay) } else { last = now; fun.apply(that, _args); } } } let throttleAjax = throttle(ajax, 1000) let inputThrottle = document.getElementById('throttle') inputThrottle.addEventListener('keyup', function (e) { throttleAjax(e.target.value) })
從上面代碼能夠看出,規定每一秒執行一次ajax請求,效果圖也能比較清晰的反應出來。app
函數防抖是某一段時間內只執行一次;而函數節流是間隔時間執行,無論事件觸發有多頻繁,都會保證在規定時間內必定會執行一次真正的事件處理函數。函數
在其餘同窗的文章中看到這樣的解釋:
防抖 — 若是有人進電梯(觸發事件),那電梯將在10秒鐘後出發(執行事件監聽器),這時若是又有人進電梯了(在10秒內再次觸發該事件),咱們又得等10秒再出發(從新計時)。
節流 — 咱們知道目前的一種說法是當 1 秒內連續播放 24 張以上的圖片時,在人眼的視覺中就會造成一個連貫的動畫,因此在電影的播放(之前是,如今不知道)中基本是以每秒 24 張的速度播放的,爲何不 100 張或更可能是由於 24 張就能夠知足人類視覺需求的時候,100 張就會顯得很浪費資源。
這大概能夠較爲清晰的講出這二者的區別吧。
防抖是維護一個計時器,規定在delay時間後觸發函數,可是在delay時間內再次觸發的話,都會清除當前的 timer 而後從新設置超時調用,即從新計時。這樣一來,只有最後一次操做能被觸發。
節流是經過判斷是否到達必定時間來觸發函數,若沒到規定時間則使用計時器延後,而下一次事件則會從新設定計時器。
文章來源
1.詳談js防抖和節流
2.輕鬆理解JS函數節流和函數防抖
3.函數防抖和節流
好啦,今天的小菊花課堂之JS的防抖與節流的內容就告一段落啦,感各位能耐心看到這裏。
see u ~ again