du blog
Hello, welcome to my blog
从lodash看节流和防抖
created: Apr 26 21updated: Apr 26 21
1function debounce(func, wait, options) { 2 var lastArgs, 3 lastThis, 4 maxWait, // 最大等待时长 5 result,// 结果 6 timerId, 7 lastCallTime, // 最后调用时间 8 lastInvokeTime = 0,// 最后调用真实函数时间 9 leading = false, // 是否在第一次时调用真实函数 10 maxing = false, // 是否传入最大等待时长 11 trailing = true; //是否在最后一次调用函数 12 13 14 if (typeof func != 'function') { 15 throw new TypeError(FUNC_ERROR_TEXT); 16 } 17 wait = toNumber(wait) || 0; 18 if (isObject(options)) { 19 leading = !!options.leading; 20 maxing = 'maxWait' in options; 21 maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; 22 trailing = 'trailing' in options ? !!options.trailing : trailing; 23 } 24 25 26 // 调用真实函数 27 function invokeFunc(time) { 28 var args = lastArgs, 29 thisArg = lastThis; 30 31 32 lastArgs = lastThis = undefined; 33 lastInvokeTime = time; 34 result = func.apply(thisArg, args); 35 return result; 36 } 37 38 39 function leadingEdge(time) { 40 // Reset any `maxWait` timer. 41 lastInvokeTime = time; 42 // Start the timer for the trailing edge. 43 timerId = setTimeout(timerExpired, wait); 44 // Invoke the leading edge. 45 return leading ? invokeFunc(time) : result; 46 } 47 48 function remainingWait(time) { 49 var timeSinceLastCall = time - lastCallTime, 50 timeSinceLastInvoke = time - lastInvokeTime, 51 timeWaiting = wait - timeSinceLastCall; 52 53 54 return maxing 55 ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) 56 : timeWaiting; 57 } 58 // 是否应该调用真实函数 59 function shouldInvoke(time) { 60 var timeSinceLastCall = time - lastCallTime, 61 timeSinceLastInvoke = time - lastInvokeTime; 62 63 64 // Either this is the first call, activity has stopped and we're at the 65 // trailing edge, the system time has gone backwards and we're treating 66 // it as the trailing edge, or we've hit the `maxWait` limit. 67 // 首次调用、活动停止到达延迟的节点、系统时间倒退作为后沿、已经达到了maxWait的限制 68 return (lastCallTime === undefined || (timeSinceLastCall >= wait) || 69 (timeSinceLastCall < 0) || (maxing &amp;&amp; timeSinceLastInvoke >= maxWait)); 70 } 71 72 73 function timerExpired() { 74 var time = now(); 75 if (shouldInvoke(time)) { 76 return trailingEdge(time); 77 } 78 // Restart the timer. 79 timerId = setTimeout(timerExpired, remainingWait(time)); 80 } 81 82 83 function trailingEdge(time) { 84 timerId = undefined; 85 86 87 // Only invoke if we have `lastArgs` which means `func` has been 88 // debounced at least once. 89 // 只有当lastArgs有值时才调用func,这表示debounced 至少被调用了一次 90 if (trailing &amp;&amp; lastArgs) { 91 return invokeFunc(time); 92 } 93 lastArgs = lastThis = undefined; 94 return result; 95 } 96 97 98 function cancel() { 99 if (timerId !== undefined) { 100 clearTimeout(timerId); 101 } 102 lastInvokeTime = 0; 103 lastArgs = lastCallTime = lastThis = timerId = undefined; 104 } 105 106 107 function flush() { 108 return timerId === undefined ? result : trailingEdge(now()); 109 } 110 111 112 function debounced() { 113 var time = now(), 114 isInvoking = shouldInvoke(time); 115 116 117 lastArgs = arguments; 118 lastThis = this; 119 lastCallTime = time; 120 if (isInvoking) { 121 122 123 if (timerId === undefined) { 124 return leadingEdge(lastCallTime); 125 } 126 if (maxing) { 127 // Handle invocations in a tight loop. 128 clearTimeout(timerId); 129 timerId = setTimeout(timerExpired, wait); 130 return invokeFunc(lastCallTime); 131 } 132 } 133 // if (timerId === undefined) { 134 // timerId = setTimeout(timerExpired, wait); 135 // } 136 return result; 137 } 138 debounced.cancel = cancel; 139 debounced.flush = flush; 140 return debounced; 141} 142 143 144