javascript - 關於函數節流,定時器裡的fn.applay()感覺好詭異?
女神的闺蜜爱上我
女神的闺蜜爱上我 2017-06-14 10:52:57
0
2
723

程式碼不複雜,邏輯很簡單,就是函數節流,我直接放程式碼了。

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() 卻被執行了,求大神告知原理何在啊?還是我這段程式碼本身有問題?

女神的闺蜜爱上我
女神的闺蜜爱上我

全部回覆(2)
代言

除了setTimeout裡的之外,在

if (last && now < last + threshhold) { \*...*\ }
else {
     last = now
     fn.apply(context, args) //这里还有一个fn.apply()
}

在改變瀏覽器大小時,else裡的這個fn.apply會每隔threshhold毫秒執行一次

所以setTimeout確實只執行了一次,其餘的次數是else裡的fn.apply執行的

某草草

一次改變尺寸的操作會觸發多次onresize,第一次會觸發else的內容,其他的觸發if裡面的內容,由於你clearTimeout()寫在setTimeout前面,那最後一次setTimeout的內容會被執行,所以一次改變尺寸會觸發兩次doSomthing,而打印出來的count至少會相差2,你要是每次改變尺寸的操作事件大於250ms小於1s,那count的值會更大。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板