欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談JavaScript節(jié)流和防抖函數(shù)

 更新時間:2020年08月25日 09:05:40   作者:kenzid  
這篇文章主要介紹了JavaScript節(jié)流和防抖函數(shù)的相關(guān)資料,幫助大家更好的理解和學習JavaScript,感興趣的朋友可以了解下

概念

節(jié)流函數(shù)

間隔固定的時間執(zhí)行傳入的方法

目的是防止函數(shù)執(zhí)行的頻率過快,影響性能.常見于跟滾動,鼠標移動事件綁定的功能.

防抖函數(shù)

對于接觸過硬件的人也許更好理解,硬件按鈕按下時,由于用戶按住時間的長短不一,會多次觸發(fā)電流的波動,加一個防抖函數(shù)就會只觸發(fā)一次,防止了無意義的電流波動引起的問題.

按鍵防反跳(Debounce)為什么要去抖動呢?機械按鍵在按下時,并非按下就接觸的很好,尤其是有簧片的機械開關(guān),會在接觸的瞬間反復的開合多次,直到開關(guān)狀態(tài)完全改變。

應用在前端時,常見的場景是,輸入框打字動作結(jié)束一段時間后再去觸發(fā)查詢/搜索/校驗,而不是每打一個字都要去觸發(fā),造成無意義的ajax查詢等,或者與調(diào)整窗口大小綁定的函數(shù),其實只需要在最后窗口大小固定之后再去執(zhí)行動作.

自己的實現(xiàn)

防抖函數(shù)

關(guān)鍵點在于每次觸發(fā)時都清空延時函數(shù)的手柄,只有最后一次觸發(fā)不會清空手柄,所以最后一次觸發(fā)會等默認的1s后去執(zhí)行debounce傳入的參數(shù)函數(shù)f. debounce內(nèi)部返回的閉包函數(shù),是真正每次被調(diào)用觸發(fā)的函數(shù),不再是原本的f,所以這里的arguments取閉包函數(shù)環(huán)境變量中的arguments并在執(zhí)行f時傳給f,在setTimeout函數(shù)的外面取得.

let debounce = function(f, interval = 1000) {
 let handler = null;
 return function() {
  if (handler) {
  clearTimeout(handler);
  }
  let arg = arguments;
  handler = setTimeout(function() {
  f.apply(this, arg);
  clearTimeout(handler);
  }, interval)
 }
 }

應用:

let input = document.querySelector('#input');
 input.addEventListener('input', debounce(function(e) {
 console.log("您的輸入是",e.target.value)
 }))

更高級的實現(xiàn)還會考慮到,以leading和trailing作為參數(shù),起始先執(zhí)行一次函數(shù)并消除后面的抖動,還是最后執(zhí)行一下函數(shù),消除前面的抖動,如同我這里的例子.后面分析loadash的防抖函數(shù)時會詳細解析.

節(jié)流函數(shù)

let throttle = function(f,gap = 300){
  let lastCall = 0;
  return function(){
  let now = Date.now();
  let ellapsed = now - lastCall;
  if(ellapsed < gap){
   return
  }
  f.apply(this,arguments);
  lastCall = Date.now();
  }
 }

閉包函數(shù)在不斷被調(diào)用的期間,去記錄離上一次調(diào)用間隔的時間,如果間隔時間小于節(jié)流設(shè)置的時間則直接返回,不去執(zhí)行真正被包裹的函數(shù)f.只有間隔時間大于了節(jié)流函數(shù)設(shè)置的時間gap,才調(diào)用f,并更新調(diào)用時間.

應用:

document.addEventListener('scroll', throttle(function (e) {
 // 判斷是否滾動到底部的邏輯
 console.log(e,document.documentElement.scrollTop);
 }));

lodash源碼分析

以上是對節(jié)流防抖函數(shù)最基礎(chǔ)簡單的實現(xiàn),我們接下來分析一下lodash庫中節(jié)流防抖函數(shù)的分析.

節(jié)流函數(shù)的使用

$(window).on('scroll', _.debounce(doSomething, 200));
function debounce(func, wait, options) {
 var lastArgs,
  lastThis,
  result,
  timerId,
  lastCallTime = 0,
  lastInvokeTime = 0,
  leading = false,
  maxWait = false,
  trailing = true;

 if (typeof func != 'function') {
  throw new TypeError(FUNC_ERROR_TEXT);
 }
 wait = wait || 0;
 if (isObject(options)) {
  leading = !!options.leading;
  maxWait = 'maxWait' in options && Math.max((options.maxWait) || 0, wait);
  trailing = 'trailing' in options ? !!options.trailing : trailing;
 }

 function invokeFunc(time) {
  var args = lastArgs,
  thisArg = lastThis;

  lastArgs = lastThis = undefined;
  lastInvokeTime = time;
  result = func.apply(thisArg, args);
  return result;
 }

 function leadingEdge(time) {
  console.log("leadingEdge setTimeout")
  // Reset any `maxWait` timer.
  lastInvokeTime = time;
  // Start the timer for the trailing edge.
  timerId = setTimeout(timerExpired, wait);
  // Invoke the leading edge.
  return leading ? invokeFunc(time) : result;
 }

 function remainingWait(time) {
  var timeSinceLastCall = time - lastCallTime,
  timeSinceLastInvoke = time - lastInvokeTime,
  result = wait - timeSinceLastCall;
  console.log("remainingWait",result)
  return maxWait === false ? result : Math.min(result, maxWait - timeSinceLastInvoke);
 }

 function shouldInvoke(time) {
  console.log("shouldInvoke")
  var timeSinceLastCall = time - lastCallTime,
  timeSinceLastInvoke = time - lastInvokeTime;
  console.log("time",time,"lastCallTime",lastCallTime,"timeSinceLastCall",timeSinceLastCall)
  console.log("time",time,"lastInvokeTime",lastInvokeTime,"timeSinceLastInvoke",timeSinceLastInvoke)
  console.log("should?",(!lastCallTime || (timeSinceLastCall >= wait) ||
  (timeSinceLastCall < 0) || (maxWait !== false && timeSinceLastInvoke >= maxWait)))
  // Either this is the first call, activity has stopped and we're at the
  // trailing edge, the system time has gone backwards and we're treating
  // it as the trailing edge, or we've hit the `maxWait` limit.
  return (!lastCallTime || (timeSinceLastCall >= wait) ||
  (timeSinceLastCall < 0) || (maxWait !== false && timeSinceLastInvoke >= maxWait));
 }

 function timerExpired() {
  console.log("timerExpired")
  var time = Date.now();
  if (shouldInvoke(time)) {
  return trailingEdge(time);
  }
  console.log("Restart the timer.",time,remainingWait(time))
  // Restart the timer.
  console.log("timerExpired setTimeout")
  timerId = setTimeout(timerExpired, remainingWait(time));
 }

 function trailingEdge(time) {
  clearTimeout(timerId);
  timerId = undefined;

  // Only invoke if we have `lastArgs` which means `func` has been
  // debounced at least once.
  console.log("trailing",trailing,"lastArgs",lastArgs)
  if (trailing && lastArgs) {
  return invokeFunc(time);
  }
  lastArgs = lastThis = undefined;
  return result;
 }

 function cancel() {
  if (timerId !== undefined) {
  clearTimeout(timerId);
  }
  lastCallTime = lastInvokeTime = 0;
  lastArgs = lastThis = timerId = undefined;
 }

 function flush() {
  return timerId === undefined ? result : trailingEdge(Date.now());
 }

 function debounced() {
  var time = Date.now(),
  isInvoking = shouldInvoke(time);
  console.log("time",time);
  console.log("isInvoking",isInvoking);
  lastArgs = arguments;
  lastThis = this;
  lastCallTime = time;

  if (isInvoking) {
  if (timerId === undefined) {
   return leadingEdge(lastCallTime);
  }
  // Handle invocations in a tight loop.
  clearTimeout(timerId);
  console.log("setTimeout")
  timerId = setTimeout(timerExpired, wait);
  return invokeFunc(lastCallTime);
  }
  return result;
 }
 debounced.cancel = cancel;
 debounced.flush = flush;
 return debounced;
 }

ref

https://css-tricks.com/debouncing-throttling-explained-examples/

https://github.com/lodash/lodash/blob/4.7.0/lodash.js#L9840

https://jinlong.github.io/2016/04/24/Debouncing-and-Throttling-Explained-Through-Examples/

以上就是淺談JavaScript節(jié)流和防抖函數(shù)的詳細內(nèi)容,更多關(guān)于JavaScript節(jié)流和防抖函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論