• 页面优化:减少DOM操作,防止高频操作DOM造成页面挂掉

我们在平时开发的过程中,会有一些场景:如input框输入内容去调接口,以及onmousemove,resize,onscroll等,正常情况会频繁的去触发事件,造成不必要的性能消耗,为了避免这种情况就会通过函数防抖和函数节流来处理。

函数防抖

  • _.debounce(func, [wait=0], [immediate])

    事件响应函数(func)在一段时间(wait)后才会执行,如果在这段时间内再次触发该函数,会重新计算执行时间;当预定的时间内没有再次调用该函数,则执行func。

  • 应用场景

    • scroll时间滚动触发
    • 搜索框输入查询
    • 表单验证
    • 按钮提交
    • 浏览器窗口缩放,resize事件 ```javascript // 防抖函数 function debounce(func, wait, immediate) { let timeout; let result;

    let debounced = function() { // this指向 let context = this; // event let args = arguments;

    1. clearTimeout(timeout);

    if(immediate) {

    1. let callNow = !timeout;
    2. timeout = setTimeout(function() {
    3. timeout = null;
    4. }, wait);
    5. // 立即执行
    6. if(callNow) {
    7. result = func.apply(context, args);
    8. }

    } else {

    1. timeout = setTimeout(function() {
    2. func.apply(context, args);
    3. }, wait);

    }

    return result; }

    debounced.cancel = function() {

    1. clearTimeout(timeout);

    timeout = null; }

    return debounced; } ```

    函数节流

  • _.throttle(func, [wait=0], [options])

    如果持续触发事件,每隔一段时间,只执行一次

  • 应用场景

    • DOM元素的拖拽功能实现
    • 射击游戏
    • 计算鼠标的移动距离
    • 监听scroll滚动事件 ```javascript // 节流函数 // 1、使用时间戳节流 // 第一次触发,最后一次不触发 function throttle(func, wait) { let context; let args;

    // 上一次执行的时间戳 let old = 0; return function() { context = this; args = arguments;

    1. // 获取当前时间戳

    let now = Date.now();

    if(now - old > wait) {

    1. // 立即执行
    2. func.apply(context, args);
    3. // 时间戳改变
    4. old = now;

    } } }

// 2、使用定时器 // 第一次不触发,最后一次触发 function throttle(func, wait) { let timeout; let context; let args;

return function() { context = this; args = arguments;

  1. if(!timeout) {
  2. timeout = setTimeout(function() {
  3. timeout = null;
  4. func.apply(context, args);
  5. }, wait);
  6. }

} }

// 3、时间戳和定时器结合 // 第一次触发,最后一次触发 function throttle(func, wait, options) { let timeout; let context; let args;

// 上一次执行的时间戳 let old = 0;

return function() { context = this; args = arguments; // 获取当前时间戳 let now = Date.now();

  1. if(!options.leading && !old) {
  2. old = now;
  3. }
  4. if(now - old > wait) {
  5. // 第一次执行
  6. if(timeout) {
  7. clearTimeout(timeout);
  8. timeout = null;
  9. }
  10. // 立即执行
  11. func.apply(context, args);
  12. // 时间戳改变
  13. old = now;
  14. } else if(!timeout && options.trailing) {
  15. // 最后一次执行
  16. timeout = setTimeout(function() {
  17. old = Date.now();
  18. timeout = null;
  19. func.apply(context, args);
  20. }, wait);
  21. }

} } ```