articles icon indicating copy to clipboard operation
articles copied to clipboard

滚动防抖引发的一个莫名其妙的bug

Open axuebin opened this issue 6 years ago • 0 comments

问题描述

一开始这个 bug 是在 weex 下遇到的,使用的是 weex 自己的 scroller 组件,需要对滑动操作做防抖,会出现3s左右的延迟。

image image image

问题定位

做了几个组合实验来排除可能性:

  1. weex 滚动组件 @scroll+setTimeout(会出现)
  2. [email protected]+setTimeout(单独测试不会出现,项目中会出现)
  3. weex 滚动组件 @scroll.native+setTimeout(会出现)

剥离业务代码后的代码如下:

let timeout = 0;
let time = '';
export default {
    methods: {
        onScroll() {
            time = Date.now();
            console.log('滚动', time);
            clearTimeout(timeout);
            timeout = setTimeout(() => {
                time = Date.now();
                console.log('触发', time);
            }, 1000);
        },
    },
};

setTimeout(() => {}, delay)delay 设置超过3s就是正常设置的时间,如果设置的 delay 小于3s,就会出现3s延迟。

setTimeout(() => {}, 0) 也会出现这个问题,setImmediate() 不会出现这个问题,但是就不起防抖的作用。

然而没有找出问题所在。。。

解决方法

暂时使用 requestAnimationFrame 替代 setTimeout

setRaf() {
    this.raf = requestAnimationFrame(() => {
        this.rafTimes += 1;
        if (this.rafTimes >= 20) {
            this.scrollBody(); // 触发实际滚动方法
            this.rafTimes = 0;
        } else {
            this.setRaf();
        }
    });
},
onScroll() {
    if (requestAnimationFrame) {
        this.rafTimes = 0;
        cancelAnimationFrame(this.raf);
        this.setRaf();
    } else {
        this.scrollBody(); // 触发实际滚动方法
    }
},

由于 requestAnimationFrame 存在兼容性问题,首先需要进行一下判断:

const requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
const cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame;

最好的方式应该是要对 requestAnimationFrame 进行 polyfill 的,但是 requestAnimationFramepolyfill 会用到 setTimeout ,还是会延时,所以在不支持 requestAnimationFrame 的环境下只能不做防抖了。

求助

如果有谁知道这是为什么的,一定一定要告诉我 ~ 谢谢 ~

axuebin avatar Jul 23 '18 09:07 axuebin