首頁 > web前端 > js教程 > 主體

JavaScript函數節流概念與用法實例詳解

高洛峰
發布: 2016-12-29 10:04:47
原創
1263 人瀏覽過

本文實例講述了JavaScript函數節流概念與用法。分享給大家供大家參考,具體如下:

最近在做網頁的時候有個需求,就是瀏覽器視窗改變的時候需要改一些頁面元素大小,於是乎很自然的想到了window的resize事件,於是乎我是這麼寫的

<!DOCTYPE html>
<html>
<head>
  <title>Throttle</title>
</head>
<body>
  <script type="text/javascript">
    n=0;
    function resizehandler(){
      console.log(new Date().getTime());
      console.log(++n);
    }
    window.onresize=resizehandler;
  </script>
</body>
</html>
登入後複製

功能倒是實現了,但是我拖拽的方式改變瀏覽器窗口大小的時候看了下控制台

沒錯,簡單的一個拖拽讓我的resizeHandler()方法執行了52次,這完全不是我想要的效果,實際上我的resizeHandler()方法的程式碼很複雜,甚至會使用ajax向伺服器發送請求,要是簡單的一次改變視窗大小就要調用52次這還了得

函數節流

其實我的本意只是視窗resize後頁面做一些調整就可以,而window的resize事件並不是在resize結束後才觸發的,具體則麼個頻率我也不知道,但卻是在不停的調用,直到視窗大小不再變化。其實類似的機制還有滑鼠的mousemove,都是在短時間內重複觸發。

在《JavaScript高級程式設計》中有專門應對此問題的函數節流

function throttle(method,context){
  clearTimeout(method.tId);
  method.tId=setTimeout(function(){
    method.call(context);
  },500);
}
登入後複製

原理很簡單,利用定時器,讓函數執行延遲500毫秒,在500毫秒內如果有函數又被調用則刪除上一次調用,這次調用500毫秒後執行,如此往復。這樣我剛才的程式碼可以改為

<script type="text/javascript">
n=0;
function resizehandler(){
  console.log(new Date().getTime());
  console.log(++n);
}
function throttle(method,context){
  clearTimeout(method.tId);
  method.tId=setTimeout(function(){
    method.call(context);
  },500);
}
window.onresize=function(){
  throttle(resizehandler,window);
};
</script>
登入後複製

拖曳一下試試,果真只執行了一次

另一種做法

網上還有一種函數節流方案,它是這麼做的

function throttle(method,delay){
  var timer=null;
  return function(){
    var context=this, args=arguments;
    clearTimeout(timer);
    timer=setTimeout(function(){
      method.apply(context,args);
    },delay);
  }
}
登入後複製

調用試試試,一樣的效果

<script type="text/javascript">
n=0;
function resizehandler(){
  console.log(new Date().getTime());
  console.log(++n);
}
function throttle(method,delay){
  var timer=null;
  return function(){
    var context=this, args=arguments;
    clearTimeout(timer);
    timer=setTimeout(function(){
      method.apply(context,args);
    },delay);
  }
}
window.onresize=throttle(resizehandler,500);//因为返回函数句柄,不用包装函数了
</script>
登入後複製

JavaScript函數節流概念與用法實例詳解

比較

兩種方法都是利用了setTimeout,不同的是第二種方法加入的函數延遲執行時間,這個在第一種方案中很容易也具有此功能,加一個參數的事兒。

但第一種方案把tId設為函數的一個變數保存,而第二種創建了一個閉包來儲存。個人覺得差距不大,很喜歡第一種,簡單,有效率。

新需求

有一天做了個類似的東西,就像百度首頁輸入自動提示一樣的東西,我在text上綁定keyup事件,每次鍵盤彈起的時候自動提示,但是又不想提示那麼頻繁,於是我用了上面方法,但是悲劇了,只有停止輸入等500毫秒才會提示,在輸入過程中根本就沒有提示。看了一下程式碼,可不是嘛,只要是使用者會盲打,在500毫秒內按一下鍵盤,提示函數就會不斷被延遲,這樣只有停下來的時候才會提示,這就沒意義了。

能不能在函數節流的基礎上間隔固定時間就執行一次?

小改動

在網上搜了一下我們可以根據第二種寫法(第一種為函數拓展多個變量感覺有些不好)做些改動,添加一個參數作為到固定間隔必須執行

function throttle(method,delay,duration){
  var timer=null, begin=new Date();
  return function(){
    var context=this, args=arguments, current=new Date();;
    clearTimeout(timer);
    if(current-begin>=duration){
       method.apply(context,args);
       begin=current;
    }else{
      timer=setTimeout(function(){
        method.apply(context,args);
      },delay);
    }
  }
}
登入後複製

這樣每次我們判斷間隔了多久,要是超過設定時間則立即執行一次,以剛才例子試一試效果

window.onresize=throttle(resizehandler,100,200);
登入後複製

JavaScript函數節流概念與用法實例詳解

果真既沒有頻繁執行也沒有就最後執行

希望本文所述對JavaScript程式設計有所幫助。

更多JavaScript函數節流概念與用法實例詳解相關文章請關注PHP中文網!



相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!