當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
JavaScript函数节流和函数防抖
生活随笔
收集整理的這篇文章主要介紹了
JavaScript函数节流和函数防抖
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1.為什么需要函數(shù)防抖和函數(shù)節(jié)流?
- 在瀏覽器中某些計算和處理要比其他的昂貴很多。例如DOM操作比起非DOM交互需要更多的內存和CPU占用時間。連續(xù)嘗試進行過多的DOM操作可能會導致瀏覽器掛起,甚至崩潰;
- 例如當調整瀏覽器大小的時候,resize事件會連續(xù)觸發(fā);如果在resize事件處理程序內部嘗試進行DOM操作,其高頻率的更改可能會讓瀏覽器崩潰;
- 為了繞開上面的問題,需要對該類函數(shù)進行節(jié)流;
2.什么是函數(shù)防抖和函數(shù)節(jié)流
防抖(debounce)和節(jié)流(throttle)都是用來控制某個函數(shù)在一定時間內執(zhí)行多少次的技巧,兩者相似而又不同。背后的基本思想是?某些代碼不可以連續(xù)重復執(zhí)行。
2.1 函數(shù)防抖 (debounce)--講究保留最后一次
如果一個事件被頻繁觸發(fā)多次,并且觸發(fā)的時間間隔過短,則防抖函數(shù)可以使得對應的事件處理函數(shù)只執(zhí)行最后觸發(fā)的一次。函數(shù)防抖可以把多個順序的調用合并成一次。
2.2 函數(shù)節(jié)流 (throttle)--講究頻率
如果一個事件被頻繁觸發(fā)多次,節(jié)流函數(shù)可以按照固定頻率去執(zhí)行對應的事件處理方法。函數(shù)節(jié)流保證一個事件一定時間內只執(zhí)行一次。
3.應用場景
| 函數(shù)防抖 | 1. 手機號、郵箱輸入檢測 2. 搜索框搜索輸入(只需最后一次輸入完后,再放松Ajax請求) 3. 窗口大小resize(只需窗口調整完成后,計算窗口大小,防止重復渲染) 4. 滾動事件scroll(只需執(zhí)行觸發(fā)的最后一次滾動事件的處理程序) 5. 文本輸入的驗證(連續(xù)輸入文字后發(fā)送 AJAX 請求進行驗證,(停止輸入后)驗證一次就好) |
| 函數(shù)節(jié)流 | 1.?DOM元素的拖拽功能實現(xiàn)(mousemove) 2. 射擊游戲的?mousedown/keydown?事件(單位時間只能發(fā)射一顆子彈) 3. 計算鼠標移動的距離(mousemove) 4. 搜索聯(lián)想(keyup) 5. 滾動事件scroll,(只要頁面滾動就會間隔一段時間判斷一次) |
4.如何實現(xiàn)
4.1 函數(shù)防抖實現(xiàn)
function debounce(fn, delay, scope) {let timer = null;// 返回函數(shù)對debounce作用域形成閉包return function () {// setTimeout()中用到函數(shù)環(huán)境總是window,故需要當前環(huán)境的副本;let context = scope || this, args = arguments;// 如果事件被觸發(fā),清除timer并重新開始計時clearTimeout(timer);timer = setTimeout(function () {fn.apply(context, args);}, delay);} }第一次調用函數(shù),創(chuàng)建一個定時器,在指定的時間間隔之后運行代碼; 當?shù)诙握{用該函數(shù)時,它會清除前一次的定時器并設置另一個; 如果前一個定時器已經執(zhí)行過了,這個操作就沒有任何意義; 然而,如果前一個定時器尚未執(zhí)行,其實就是將其替換為一個新的定時器; 目的是只有在執(zhí)行函數(shù)的請求停止了delay時間之后才執(zhí)行。4.2 函數(shù)節(jié)流實現(xiàn)
4.2.1 利用時間戳簡單實現(xiàn)
function throttle(fn, threshold, scope) {let timer;let prev = Date.now();return function () {let context = scope || this, args = arguments;let now = Date.now();if (now - prev > threshold) {prev = now;fn.apply(context, args);}} }4.2.2 利用定時器簡單實現(xiàn)
function throttle2(fn, threshold, scope) {let timer;return function () {let context = scope || this, args = arguments;if (!timer) {timer = setTimeout(function () {fn.apply(context, args);timer = null;}, threshold);}} }5 舉例(scroll事件)
CSS代碼
.wrap {width: 200px;height: 330px;margin: 50px;margin-top: 200px;position: relative;float: left;background-color: yellow;}.header{width: 100%;height: 30px;background-color: #a8d4f4;text-align: center;line-height: 30px;}.container {background-color: pink;box-sizing: content-box;width: 200px;height: 300px;overflow: scroll;position: relative;}.content {width: 140px;height: 800px;margin: auto;background-color: #14ffb2;}HTML代碼
<div class="wrap"><div class="header">滾動事件:普通</div><div class="container"><div class="content"></div></div></div><div class="wrap"><div class="header">滾動事件:<strong>加了函數(shù)防抖</strong></div><div class="container"><div class="content"></div></div></div><div class="wrap"><div class="header">滾動事件:<strong>加了函數(shù)節(jié)流</strong></div><div class="container"><div class="content"></div></div></div>JS代碼
let els = document.getElementsByClassName('container');let count1 = 0,count2 = 0,count3 = 0;const THRESHOLD = 200;els[0].addEventListener('scroll', function handle() {console.log('普通滾動事件!count1=', ++count1);});els[1].addEventListener('scroll', debounce(function handle() {console.log('執(zhí)行滾動事件!(函數(shù)防抖) count2=', ++count2);}, THRESHOLD));els[2].addEventListener('scroll', throttle(function handle() {console.log(Date.now(),', 執(zhí)行滾動事件!(函數(shù)節(jié)流) count3=', ++count3);}, THRESHOLD));函數(shù)防抖
// 函數(shù)防抖 function debounce(fn, delay, scope) {let timer = null;let count = 1;return function () {let context = scope || this,args = arguments;clearTimeout(timer);console.log(Date.now(), ", 觸發(fā)第", count++, "次滾動事件!");timer = setTimeout(function () {fn.apply(context, args);console.log(Date.now(), ", 可見只有當高頻事件停止,最后一次事件觸發(fā)的超時調用才能在delay時間后執(zhí)行!");}, delay);} }函數(shù)節(jié)流
// 函數(shù)節(jié)流 function throttle(fn, threshold, scope) {let timer;let prev = Date.now();return function () {let context = scope || this, args = arguments;let now = Date.now();if (now - prev > threshold) {prev = now;fn.apply(context, args);}} }效果截圖
?
6.總結
總結
以上是生活随笔為你收集整理的JavaScript函数节流和函数防抖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript的JSON转变函数p
- 下一篇: 第五章 常用Lua开发库2-JSON库、