articles
articles copied to clipboard
滚动防抖引发的一个莫名其妙的bug
问题描述
一开始这个 bug 是在 weex 下遇到的,使用的是 weex 自己的 scroller 组件,需要对滑动操作做防抖,会出现3s左右的延迟。

问题定位
做了几个组合实验来排除可能性:
weex滚动组件@scroll+setTimeout(会出现)[email protected]+setTimeout(单独测试不会出现,项目中会出现)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 的,但是 requestAnimationFrame 的 polyfill 会用到 setTimeout ,还是会延时,所以在不支持 requestAnimationFrame 的环境下只能不做防抖了。
求助
如果有谁知道这是为什么的,一定一定要告诉我 ~ 谢谢 ~