程式碼不複雜,邏輯很簡單,就是函數節流,我直接放程式碼了。
var count = 0
setInterval(() => console.log(new Date().getSeconds()),1000)
function doSomthing() {
console.log('懵逼。。。。')
count ++;
}
window.onresize = throttle(doSomthing,1000)
function throttle(fn, threshhold) {
// 记录上次执行的时间
var last
// 定时器
var timer
// 默认间隔为 250ms
threshhold || (threshhold = 250)
// 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数
return function () {
// 保存函数调用时的上下文和参数,传递给 fn
var context = this
var args = arguments
var now = +new Date()
// 如果距离上次执行 fn 函数的时间小于 threshhold,那么就放弃
// 执行 fn,并重新计时
if (last && now < last + threshhold) {
clearTimeout(timer)
// 保证在当前时间区间结束后,再执行一次 fn
timer = setTimeout(function () {
last = now
console.log('第'+count+'次执行')
fn.apply(context, args)
}, threshhold)
// 在时间区间的最开始和到达指定间隔的时候执行一次 fn
} else {
last = now
fn.apply(context, args)
}
}
}
理論上當我不斷改變瀏覽器視窗大小的時候(就是說間隔肯定小於1s的),doSomthing
從第二次開始是不會被執行的。因為我在不斷的執行cleraTimeout
,實際運行結果是 console.log('第' count '次執行)
確實沒有被打印出來,但是當我停止改變瀏覽器窗口的時候,發現印出來的count
並不是1
#,而且是一個很大的數字。
這說明,在這段程式碼裡:
timer = setTimeout(function () {
last = now
console.log('第'+count+'次执行')
fn.apply(context, args)
}, threshhold)`
setTimeout()
裡的匿名函數沒有被執行,但是匿名函數裡的 fn.apply()
卻被執行了,求大神告知原理何在啊?還是我這段程式碼本身有問題?
除了
setTimeout
裡的之外,在在改變瀏覽器大小時,else裡的這個
fn.apply
會每隔threshhold毫秒執行一次所以
setTimeout
確實只執行了一次,其餘的次數是else裡的fn.apply
執行的一次改變尺寸的操作會觸發多次onresize,第一次會觸發else的內容,其他的觸發if裡面的內容,由於你clearTimeout()寫在setTimeout前面,那最後一次setTimeout的內容會被執行,所以一次改變尺寸會觸發兩次doSomthing,而打印出來的count至少會相差2,你要是每次改變尺寸的操作事件大於250ms小於1s,那count的值會更大。