美文网首页
Javascript 函数节流和函数去抖场景介绍

Javascript 函数节流和函数去抖场景介绍

作者: 天外来人 | 来源:发表于2016-03-16 15:10 被阅读669次

函数节流场景
例如:实现一个原生的拖拽功能(如果不用H5 Drag和Drop API),我们就需要一路监听mousemove事件,在回调中获取元素当前位置,然后重置dom的位置。如果我们不加以控制,每移动一定像素而出发的回调数量是会非常惊人的,回调中又伴随着DOM操作,继而引发浏览器的重排和重绘,性能差的浏览器可能会直接假死。这时,我们就需要降低触发回调的频率,比如让它500ms触发一次或者200ms,甚至100ms,这个阀值不能太大,太大了拖拽就会失真,也不能太小,太小了低版本浏览器可能会假死,这时的解决方案就是函数节流【throttle】。函数节流的核心就是:让一个函数不要执行得太频繁,减少一些过快的调用来节流。

函数去抖场景
例如:对于浏览器窗口,每做一次resize操作,发送一个请求,很显然,我们需要监听resize事件,但是和mousemove一样,每缩小(或者放大)一次浏览器,实际上会触发N多次的resize事件,这时的解决方案就是节流【debounce】。函数去抖的核心就是:在一定时间段的连续函数调用,只让其执行一次

函数节流的实现
函数节流的第一种方案封装如下

function throttleFunc(method,context)
{
  clearTimeout(method.timer);  //为什么选择setTimeout 而不是setInterval
  method.timer = setTimeout(function(){
    method.call(context);
  },100);
}

看一个封装的demo

window.onscroll = function(){
  throttleFunc(show);
}
function show(){
  console.log(1);
}
function throttleFunc(method){
  clearTimeout(method.timer);
  method.timer = setTimeout(function(){
    method();
  },100);
}

也可以使用闭包的方法对上面的函数进行再封装一次

function throttle(fn, delay) {
  var timer = null;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn();
    }, delay);
 };
};

调用

var func = throttle(show,100);
function show() {
  console.log(1);
}
window.onscroll = function() {
  func();
}

封装2

function throttle(fn, delay, runDelay) {
  var timer = null;
  var t_start;
  return function() {
    var t_cur = new Date();
    timer && clearTimeout(timer);
    if (!t_start) {
      t_start = t_cur;
    }
    if (t_cur - t_start >= runDelay) {
      fn();
      t_start = t_cur;
    } else {
      timer = setTimeout(function() {
        fn();
      }, delay);
    }
  }
}

调用

var func = throttle(show, 50,100);
function show() {
  console.log(1);
}
window.onscroll = function() {
  func();
}
函数去抖的实现:

代码在underscore的基础上进行了扩充

// 函数去抖(连续事件触发结束后只触发一次)
// sample 1: _.debounce(function(){}, 1000)
// 连续事件结束后的 1000ms 后触发
// sample 1: _.debounce(function(){}, 1000, true)
// 连续事件触发后立即触发(此时会忽略第二个参数)

_.debounce = function(func, wait, immediate) { 
  var timeout, args, context, timestamp, result; 
  var later = function() { 
    // 定时器设置的回调 later 方法的触发时间,和连续事件触发的最后一次时间戳的间隔 
    // 如果间隔为 wait(或者刚好大于 wait),则触发事件 
    var last = _.now() - timestamp; 

    // 时间间隔 last 在 [0, wait) 中 
    // 还没到触发的点,则继续设置定时器 
    // last 值应该不会小于 0 吧? 
    if (last < wait && last >= 0) { 
      timeout = setTimeout(later, wait - last); 
    } else { 
      // 到了可以触发的时间点 timeout = null; 
      // 可以触发了 
      // 并且不是设置为立即触发的 
      // 因为如果是立即触发(callNow),也会进入这个回调中 
      // 主要是为了将 timeout 值置为空,使之不影响下次连续事件的触发
      // 如果不是立即执行,随即执行 func 方法 
      if (!immediate) { 
        // 执行 func 函数 
        result = func.apply(context, args); 
        // 这里的 timeout 一定是 null 了吧 
        // 感觉这个判断多余了 
        if (!timeout)  
          context = args = null; 
        } 
     } 
   };
   // 嗯,闭包返回的函数,是可以传入参数的 
   return function() { 
    // 可以指定 this 指向 
    context = this; 
    args = arguments; 

    // 每次触发函数,更新时间戳 
    // later 方法中取 last 值时用到该变量 
    // 判断距离上次触发事件是否已经过了 wait seconds 了 
    // 即我们需要距离最后一次触发事件 wait seconds 后触发这个回调方法
    timestamp = _.now(); 
    // 立即触发需要满足两个条件 
    // immediate 参数为 true,并且 timeout 还没设置 
    // immediate 参数为 true 是显而易见的 
    // 如果去掉 !timeout 的条件,就会一直触发,而不是触发一次 
    // 因为第一次触发后已经设置了 timeout,所以根据 timeout 是否为空可以判断是否是首次触发 
    var callNow = immediate && !timeout; 

    // 设置 wait seconds 后触发 later 方法 
    // 无论是否 callNow(如果是 callNow,也进入 later 方法,去 later 方法中判断是否执行相应回调函数) 
    // 在某一段的连续触发中,只会在第一次触发时进入这个 if 分支中 
    if (!timeout) 
      // 设置了 timeout,所以以后不会进入这个 if 分支了 
      timeout = setTimeout(later, wait); 
    // 如果是立即触发 
    if (callNow) { 
      // func 可能是有返回值的 
      result = func.apply(context, args); 
      // 解除引用 
      context = args = null; 
    } 
    return result; 
  };
};

参考文献:
http://www.cnblogs.com/tugenhua0707/p/5272539.html
https://github.com/hanzichi/underscore-analysis/issues/21

相关文章

  • Javascript 函数节流和函数去抖场景介绍

    函数节流场景例如:实现一个原生的拖拽功能(如果不用H5 Drag和Drop API),我们就需要一路监听mouse...

  • 函数节流(throttle)与函数去抖(debounce)

    JavaScript-性能优化,函数节流(throttle)与函数去抖(debounce)JS魔法堂:函数节流(t...

  • JavaScript 函数节流和函数去抖

    概念 函数防抖(debounce) 当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执...

  • 函数节流与函数防抖

    函数节流与函数防抖的区别JS魔法堂:函数节流(throttle)与函数去抖(debounce)函数的防抖与节流 自...

  • 函数操作v1.0.0

    目录 函柯里化函数节流函数防抖 正文 函柯里化 函数节流 函数防抖

  • 节流函数和函数去抖

    被问到一个完全陌生的名词,于是来记录一下。争取以后不忘:) 节流函数 目的: 目的就是为了节流函数,从而优化性能。...

  • JavaScript 函数节流和函数去抖应用场景辨析

    概述 也是好久没更新 源码解读,看着房价蹭蹭暴涨,心里也是五味杂陈,对未来充满恐惧和迷茫 ...(敢问一句你们上岸...

  • 节流函数的应用场景

    vue实现输入框的模糊查询(节流函数的应用场景) 上一篇讲到了javascript的节流函数和防抖函数,那么我们在...

  • Javascript 基础

    1、函数防抖和函数节流 【《javascript高级程序设计》里,函数节流是这里讲的函数防抖。】函数防抖: 在事件...

  • 函数节流和函数去抖

    函数去抖(debounce) 在日常的开发过程中,会有这样的场景,事件被频繁的触发,比如说我们的在输入的时候监控k...

网友评论

      本文标题:Javascript 函数节流和函数去抖场景介绍

      本文链接:https://www.haomeiwen.com/subject/cbiqlttx.html