節流實質上是:如果你持續觸發事件,每隔一段時間,隻執行一次事件。
根據這個需求我們可以通過時間戳實作節流:
//第一個實作方式function throttle(func, wait) { var context, args; var previous = 0; return function() { var now = +new Date(); context = this; args = arguments; if (now - previous > wait) { func.apply(context, args); previous = now; } }}//另外補充一下擷取時間戳的方式吧// new Date().getTime()// Date.parse(new Date())// +new Date()// Date.now()// 通過判斷再次點選時間與上次點選時間的時間戳是否大于傳入的時間,來判斷函數是否被執行
另一種實作方式通過定時器,通過判斷定時器的存在來決定函數是否被執行
// 第二種實作方式function throttle(func, wait) { var timeout; var previous = 0; return function() { context = this; args = arguments; if (!timeout) { timeout = setTimeout(function(){ timeout = null; func.apply(context, args) }, wait) } }}//
看上面兩種實作方式的代碼,比較可以發現:
- 方式一的事件會立刻執行,因為擷取目前時間戳肯定會大于wait傳入的時間,方式二事件會在 n 秒後第一次執行,因為設定了定時器,是以會在wait秒之後執行。
- 如果我們連續執行了幾次,第一種方式會在事件結束之後不會再執行函數,第二種會在結束之後wait秒之後再執行一次。
怎麼中和實作一下兩種方式呢?
// 第三種方式function throttle(func, wait, options) { var timeout, context, args, result; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : new Date().getTime(); timeout = null; func.apply(context, args); if (!timeout) context = args = null; }; var throttled = function() { var now = new Date().getTime(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } }; return throttled;}
//leading:false 表示禁用第一次執行//trailing: false 表示禁用停止觸發的回調//那就是 leading:false 和 trailing: false 不能同時設定。