c++17 返回值優化
阿新 • • 發佈:2022-05-31
1、什麼是函式防抖和函式節流
防抖(debounce
)和節流(throttle
)都是用來控制某個函式在一定時間內執行多少次的技巧,兩者相似不相同,基本思想都是某些程式碼不可以在沒有間斷的情況下連續重複執行
1.1 函式防抖
如果一個事件被頻繁執行多次,並且觸發的時間間隔過短,則防抖函式可以使得對應的事件處理函式,只執行最後觸發的一次。函式防抖可以把多個順序的呼叫合併成一次。
1.2 函式節流
如果一個事件被頻繁觸發多次,節流函式可以按照固定的頻率去執行相應的事件處理方法。函式節流保證一個事件一定事件內只能執行一次。
2、應用
總的來說,函式防抖適合多次事件一次響應的情況,函式節流適合大量事件按照時間做平均分配觸發
3、實現
3.1 實現函式防抖
function debounce(fn, wait) { var timer = null; // 返回函式對debounce作用域形成閉包 return function () { var context = this var args = arguments if (timer) { // 事件被觸發,清除timer並重新開始計時 clearTimeout(timer); timer = null; } timer = setTimeout(function() { fn.apply(context, args) }, wait) } } var fn = function () { console.log('boom') } setInterval(debounce(fn,500),1000) // 第一次在1500ms後觸發,之後每1000ms觸發一次 setInterval(debounce(fn,2000),1000) // 不會觸發一次(把函式防抖看出技能讀條,如果讀條沒完成就用技能,便會失敗而且重新讀條)
1、第一次呼叫函式的時候建立了一個定時器,在指定的時間之後執行程式碼
2、當第二次呼叫該函式的時候,會清除前一次的定時器並設定另一個
3、如果前一個定時器已經執行過了,這個操作就沒有任何意義
4、當前一個定時器沒有執行的時候,就是將他替換成一個新的定時器
5、目的是隻有在執行函式的請求停止了wait時間之後才執行
3.2 實現函式節流
1)利用時間戳實現
// fn 是需要執行的函式 // wait 是時間間隔 const throttle = (fn, wait = 50) => { // 上一次執行 fn 的時間 let previous = 0 // 將 throttle 處理結果當作函式返回 return function(...args) { // 獲取當前時間,轉換成時間戳,單位毫秒 let now = +new Date() // 將當前時間和上一次執行函式的時間進行對比 // 大於等待時間就把 previous 設定為當前時間並執行函式 fn if (now - previous > wait) { previous = now fn.apply(this, args) } } } // DEMO // 執行 throttle 函式返回新函式 const betterFn = throttle(() => console.log('fn 函式執行了'), 1000) // 每 10 毫秒執行一次 betterFn 函式,但是隻有時間差大於 1000 時才會執行 fn setInterval(betterFn, 10)
2) 利用定時器實現
function throttle(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) } } }
4、例項(scro
ll
事件)
<!-- CSS樣式 --> <style> .wrap { width: 200px; height: 330px; margin: 50px; margin-top: 200px; position: relative; float: left; } .header { width: 100%; height: 30px; background-color: #a8d4f4; text-align: center; line-height: 30px; } .container { background-color: darkseagreen; box-sizing: content-box; width: 200px; height: 300px; overflow: scroll; position: relative; } .content { width: 140px; height: 800px; margin: auto; background-color: cadetblue; } </style> <!-- html --> <body> <div class="wrap"> <div class="header">滾動事件:普通</div> <div class="container"> <div class="content"></div> </div> </div> <div class="wrap"> <div class="header">滾動事件:<strong>加了函式防抖</strong></div> <div class="container"> <div class="content"></div> </div> </div> <div class="wrap"> <div class="header">滾動事件:<strong>加了函式節流</strong></div> <div class="container"> <div class="content"></div> </div> </div> </body>
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('執行滾動事件!(函式防抖) count2=', ++count2); }, THRESHOLD)); els[2].addEventListener('scroll', throttle(function handle() { console.log(Date.now(), ', 執行滾動事件!(函式節流) count3=', ++count3); }, THRESHOLD)); // 函式防抖 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(), ", 觸發第", count++, "次滾動事件!"); timer = setTimeout(function () { fn.apply(context, args); console.log(Date.now(), ", 可見只有當高頻事件停止,最後一次事件觸發的超時呼叫才能在delay時間後執行!"); }, delay); } } // 函式節流 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); } } }
執行結果: