throttle.js (2459B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 // setImmediate is only defined when running in the worker thread 8 /* globals setImmediate */ 9 10 /** 11 * From underscore's `_.throttle` 12 * http://underscorejs.org 13 * (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 14 * Underscore may be freely distributed under the MIT license. 15 * 16 * Returns a function, that, when invoked, will only be triggered at most once during a 17 * given window of time. The throttled function will run as much as it can, without ever 18 * going more than once per wait duration. 19 * 20 * @param {Function} func 21 * The function to throttle 22 * @param {number} wait 23 * The wait period 24 * @param {object} scope 25 * The scope to use for func 26 * @return {Function} The throttled function 27 */ 28 function throttle(func, wait, scope) { 29 let args, result; 30 let timeout = null; 31 let previous = 0; 32 33 const later = function () { 34 previous = Date.now(); 35 timeout = null; 36 result = func.apply(scope, args); 37 args = null; 38 }; 39 40 const throttledFunction = function () { 41 const now = Date.now(); 42 const remaining = wait - (now - previous); 43 args = arguments; 44 if (remaining <= 0) { 45 if (!isWorker) { 46 clearTimeout(timeout); 47 } 48 timeout = null; 49 previous = now; 50 result = func.apply(scope, args); 51 args = null; 52 } else if (!timeout) { 53 // On worker thread, we don't have access to privileged setTimeout/clearTimeout 54 // API which wouldn't be frozen when the worker is paused. So rely on the privileged 55 // setImmediate function which executes on the next event loop. 56 if (isWorker) { 57 setImmediate(later); 58 timeout = true; 59 } else { 60 timeout = setTimeout(later, remaining); 61 } 62 } 63 return result; 64 }; 65 66 function cancel() { 67 if (timeout) { 68 if (!isWorker) { 69 clearTimeout(timeout); 70 } 71 timeout = null; 72 } 73 previous = 0; 74 args = undefined; 75 result = undefined; 76 } 77 78 function flush() { 79 if (!timeout) { 80 return result; 81 } 82 previous = 0; 83 return throttledFunction(); 84 } 85 86 throttledFunction.cancel = cancel; 87 throttledFunction.flush = flush; 88 89 return throttledFunction; 90 } 91 92 exports.throttle = throttle;