高性能Scroll

// 简单的防抖动函数
function debounce(func, wait, immediate) {
    // 定时器变量
    var timeout;
    return function() {
        // 每次触发 scroll handler 时先清除定时器
        clearTimeout(timeout);
        // 指定 xx ms 后触发真正想进行的操作 handler
        timeout = setTimeout(func, wait);
    };
};
 
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
    console.log("Success");
}
 
// 采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
// 没采用防抖动
window.addEventListener('scroll',realFunc);
// 防抖动函数
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate & !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
 
var myEfficientFn = debounce(function() {
    // 滚动中的真正的操作
}, 250);
 
// 绑定监听
window.addEventListener('resize', myEfficientFn);
// 简单的节流函数
function throttle(func, wait, mustRun) {
    var timeout,
        startTime = new Date();

    return function() {
        var context = this,
            args = arguments,
            curTime = new Date();

        clearTimeout(timeout);
        // 如果达到了规定的触发时间间隔,触发 handler
        if(curTime - startTime >= mustRun){
            func.apply(context,args);
            startTime = curTime;
        // 没达到触发间隔,重新设定定时器
        }else{
            timeout = setTimeout(func, wait);
        }
    };
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
    console.log("Success");
}
// 采用了节流函数
window.addEventListener('scroll',throttle(realFunc,500,1000));
var ticking = false; // rAF 触发锁

function onScroll(){
  if(!ticking) {
    requestAnimationFrame(realFunc);
    ticking = true;
  }
}

function realFunc(){
    // do something...
    console.log("Success");
    ticking = false;
}
// 滚动事件监听
window.addEventListener('scroll', onScroll, false);
//rAF:16.7ms

原文来自http://mp.weixin.qq.com/s/LgwTCzBgYWBe2JFXg8YMtQ

2019.11.20更新

废话不多说直接上代码

   useEffect(() => {
    let time: NodeJS.Timeout
    let startTime: Date = new Date()
    const handleCallBack = () => {
      const { scrollY } = window
      const { clientHeight, scrollHeight } = document.documentElement
      if (clientHeight + scrollY >= scrollHeight - 60) {
        callback()
      }
    }
    // TODO:优化监听
    // requestAnimationFrame()
    const throttle = () => {
      clearTimeout(time)
      const currentTime: Date = new Date()
      if (Number(currentTime) - Number(startTime) >= mustTime) {
        // 规定时间内必须执行一次
        handleCallBack()
        startTime = currentTime
      } else
        time = setTimeout(() => {
          // 防抖动
          handleCallBack()
        }, waitTime)
    }

    window.addEventListener('scroll', throttle)
    return () => {
      window.removeEventListener('scroll', throttle)
    }
  }, [callback, mustTime, waitTime])
//这是自己写的一个基于 防抖+节流的方式实现的滚动加载监听的自定义hook 留着后面直接复制粘贴
//但是qa在测试的时候发现在安卓系统的浏览器上会有兼容的问题 如果仅仅是使用在微信上应该问题不大
useEffect(() => {
    let doing = false;
    const handleCallBack = () => {
      const { scrollY } = window
      const { clientHeight, scrollHeight } = document.documentElement || document.body
      if (clientHeight + scrollY >= scrollHeight - 60) {
        callback()
      }
      doing = false
    }
    const rafCallback = () => {
      if (doing) return
      doing = true
      window.requestAnimationFrame(handleCallBack)
    }
    window.addEventListener('scroll', rafCallback)
    return () => {
      window.removeEventListener('scroll', rafCallback)
    }
  }, [callback])
//这是使用requestAnimationFrame方法根据屏幕刷新频率(例如60Hz)在屏幕渲染每一帧结束之后出发的监听效果
//避免上面setTimeout的方式监听会引发渲染回流的问题

你可能感兴趣的:(高性能Scroll)