节流:阻止函数被动的频繁调用

简介: 节流:阻止函数被动的频繁调用

节流:阻止函数被动的频繁调用


函数节流主要是解决非用户操作导致的函数被频繁调用的问题。

节流背景

浏览器中一些事件让函数非常频繁地调用,从而造成大的性能问题。

  • window.onresize 事件。当浏览器窗口大小被拖动而改变的时候,这个事件触发的频率非常之高。
    如果我们在 window.onresize 事件函数里有一些跟 DOM 节点相关的操作,这时候浏览器可能就会吃不消而造成卡顿现象。
  • mousemove 事件。同样,如果我们给一个 div 节点绑定了拖曳事件(主要是 mousemove),当 div 节点被拖动的时候,也会频繁地触发该拖曳事件函数。
  • 上传进度。一些上传插件在真正开始上传文件之前,会对文件进行扫描并随时通知 JavaScript 函数,以便在页面中显示当前的扫描进度。通知的频率非常之高,大约一秒钟 10 次,很显然我们在页面中不需要如此频繁地去提示用户。

解决方案

其实上面的问题在于,函数被触发的频率太高,1s可能运行了 10 次,但显然我们可能500ms运行1次就够

function throttle(fn, delay = 500) {
  // 记录上一次运行时间,初始设置0
  let lastDate = 0;
  return function(...args) {
    let now = new Date() - 0;
    // 当次运行的时间和上一次时间的差值,超过500ms运行,否则不运行
    if (now - lastDate < delay) {
      return;
    }
    // 迭代上一次运行时间
    lastDate = now;
    fn.call(null, ...args);
  };
}

实现逻辑

// 1. 普通的函数
function print() {
  console.log(new Date());
}
let delay = 1000;
let lastDate = 0;
function print1() {
  let now = new Date() - 0;
  if (now - lastDate < delay) {
    return;
  }
  lastDate = now;
}
print1();
print1();
// 2. 相关内容封装
var print2 = (function() {
  let delay = 1000;
  let lastDate = 0;
  return function() {
    let now = new Date() - 0;
    if (now - lastDate < delay) {
      return;
    }
    lastDate = now;
    console.log(new Date());
  };
})();
print2();
print2();
// 3. 提取参数
var print3 = function(fn, delay = 1000) {
  let lastDate = 0;
  return function() {
    let now = new Date() - 0;
    if (now - lastDate < delay) {
      return;
    }
    lastDate = now;
    fn.apply(null, arguments);
  };
};
function print() {
  console.log(new Date());
}
let print3Demo = print3(print, 1000);
print3Demo();
print3Demo();
// 4. 再抽象一层
function throttle(fn, delay = 500) {
  let lastDate = 0;
  return function(...args) {
    let now = new Date() - 0;
    if (now - lastDate < delay) {
      return;
    }
    lastDate = now;
    fn.call(null, ...args);
  };
}
// es6
const throttle = (fn, delay = 500) => {
  let lastDate = 0
  return (...args) => {
    let now = new Date() - 0
    if (now - lastDate < delay) {
      return
    }
    lastDate = now
    fn(args)
  }
}
function print(name) {
  console.log(name, new Date());
}
var tprint = throttle(print, 100);
for (let i = 0; i < 10000000; i++) {
  tprint(1);
}
// 使用场景:
window.onresize = throttle(function() {
  console.log(1);
}, 500);

《JavaScript设计模式与开发实践》

本文主要在看《JavaScript设计模式与开发实践》,再进行总结的,作者写的很棒,作者写的throttle

// throttle 函数的原理是,将即将被执行的函数用 setTimeout 延迟一段时间执行。如果该次延迟执行还没有完成,则忽略接下来调用该函数的请求。throttle 函数接受 2 个参数,第一个参数为需要被延迟执行的函数,第二个参数为延迟执行的时间。
var throttle = function(fn, interval) {
  var __self = fn, // 保存需要被延迟执行的函数引用
    timer, // 定时器
    firstTime = true; // 是否是第一次调用
  return function() {
    var args = arguments,
      __me = this;
    if (firstTime) {
      // 如果是第一次调用,不需延迟执行
      __self.apply(__me, args);
      return (firstTime = false);
    }
    if (timer) {
      // 如果定时器还在,说明前一次延迟执行还没有完成
      return false;
    }
    timer = setTimeout(function() {
      // 延迟一段时间执行
      clearTimeout(timer);
      timer = null;
      __self.apply(__me, args);
    }, interval || 500);
  };
};
window.onresize = throttle(function() {
  console.log(1);
}, 500);


目录
相关文章
|
8天前
|
JavaScript UED
常见的触发函数的事件(实现不同的用户体验)
常见的触发函数的事件(实现不同的用户体验)
20 0
|
8天前
|
小程序 前端开发
阻止小程序事件冒泡的三种方法
阻止小程序事件冒泡的三种方法
438 0
|
6月前
节流函数和防抖函数的区别和应用
节流函数和防抖函数的区别和应用
23 0
|
7月前
layoutSubviews 调用时机
layoutSubviews 调用时机
21 0
|
8天前
|
网络协议 网络性能优化 数据中心
什么是显式拥塞通知ECN?
【4月更文挑战第23天】
23 0
什么是显式拥塞通知ECN?
|
8天前
|
JavaScript 前端开发
js事件循环机制理解
js事件循环机制理解
20 1
|
11月前
|
JavaScript 前端开发
【高频触发事件优化】封装节流和防抖
【高频触发事件优化】封装节流和防抖
121 0
|
JavaScript 前端开发
面试题:什么是事件委托? 怎么阻止默认动作? 怎么阻止事件冒泡?
面试题:什么是事件委托? 怎么阻止默认动作? 怎么阻止事件冒泡?
123 0
|
JavaScript 前端开发
DOM怎么阻止默认动作?怎么阻止冒泡事件?
有一些html元素默认的行为,比如说a标签,点击后有跳转动作; form表单中的submit类型的input有一个默认提交跳转事件;reset类型的input有重置表单行为。
85 0
debounce防抖函数减少函数调用的逻辑分析(包裹上时间的外衣,在时间还没来时,kill)
debounce防抖函数减少函数调用的逻辑分析(包裹上时间的外衣,在时间还没来时,kill)
161 0

热门文章

最新文章