防抖、节流与回流、重绘

防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
/**
 * 防抖函数
 * @author vision
 * @param {执行函数} fn
 * @param {延迟} delay
 */
export function debounce(fn, delay) {
  let timer = null;
  return function() {
    let context = this;
    let arg = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, arg);
    }, delay);
  };
}

/**
 * 防抖函数 - 箭头函数
 * @param {执行函数} fn
 * @param {延迟} delay
 */
export const debounceEs6 = (fn, delay) => {
  let timer = null;
  return (...rest) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn(rest);
    }, delay);
  };
};
节流:指定时间间隔内只会执行一次任务。

    function throttle(fn) {
      // 通过闭包保存一个标记
      let canRun = true;
      return function() {
        // 在函数开头判断标志是否为 true,不为 true 则中断函数
        if(!canRun) {
          return;
        }
        // 将 canRun 设置为 false,防止执行之前再被执行
        canRun = false;
        // 定时器
        setTimeout( () => {
          fn.call(this, arguments);
          // 执行完事件(比如调用完接口)之后,重新将这个标志设置为 true
          canRun = true;
        }, 1000);
      };
    }
重绘(repaint):当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。

常见的重绘操作有:

  • 改变元素颜色改变
  • 元素背景色
  • more ……
回流(reflow):又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。

常见的回流操作有:

  • 页面初次渲染
  • 浏览器窗口大小改变
  • 元素尺寸/位置/内容发生改变
  • 元素字体大小变化
  • 添加或者删除可见的 DOM 元素
  • 激活 CSS 伪类(:hover……)
  • more ……
重点:回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。

169721e0dc217977.png

工作中要如何避免大量使用重绘与回流?
  1. 避免频繁操作样式,可汇总后统一一次修改
  2. 尽量使用 class 进行样式修改,而不是直接操作样式
  3. 减少 DOM 的操作,可使用字符串一次性插入

以下资料来自于 https://juejin.im/post/5e096d63e51d4558381e9906#heading-29

常见的会导致回流的元素:
  • 常见的几何属性有 width、height、padding、margin、left、top、border 等等。
  • 最容易被忽略的操作:获取一些需要通过即时计算得到的属性,当你要用到像这样的属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,浏览器为了获取这些值,也会进行回流。
  • 当我们调用了 getComputedStyle 方法,或者 IE 里的 currentStyle 时,也会触发回流。原理是一样的,都为求一个“即时性”和“准确性”。
避免方式:
  1. 避免逐条改变样式,使用类名去合并样式
  2. 将 DOM “离线”,使用DocumentFragment
  3. 提升为合成层,如使用will-change
#divId {
  will-change: transform;
}
优点:
  • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
  • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
  • 对于 transform 和 opacity 效果,不会触发 layout 和 paint

注意:
部分浏览器缓存了一个 flush 队列,把我们触发的回流与重绘任务都塞进去,待到队列里的任务多起来、或者达到了一定的时间间隔,或者“不得已”的时候,再将这些任务一口气出队。但是当我们访问一些即使属性时,浏览器会为了获得此时此刻的、最准确的属性值,而提前将 flush 队列的任务出队。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值