面试时问到这个问题,是这样的:
面试官问一个关于滚动到某个位置的时候出现一个顶部的导航栏,答完之后,她接着问一滚动onscroll就会执行很多很多次,如何稀释它?为了确定她说的是“稀释”,我让她重复了遍,我给出的解决方法是,用一个变量,在事件处理的时候让它自增,判断达到一定大小就执行一次实际的事件:
var i = 0; // 累积变量
window.onscroll = function(){
i++;
if(i%500==0){
// 执行实际的事件
}
}
网上都没有找到相关类型的问题,这个问题算不算变态级的面试题?如果不是,请给出解决方案,先谢谢了。
Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
我觉得他是问
函数节流的问题?(´・_・`)_.debounce你值得拥有
如下代码不知是否可以"稀释"一些scroll。
这题关键是对面试官所谓“稀释”语义的解释。
在我看来这里这个稀释可以有三个语义
1.“稀释”——稀释的是onscroll相对于浏览器本身的触发。
2.“稀释”——稀释的是onscroll回调的执行次数。
3.“稀释”——稀释的是绑定给onscroll中具体想要执行的业务逻辑的执行次数。
第一种,无解,引擎细节不对外暴露,触发这件事本身不受编码者控制,我没看过具体实现,但是猜测一下,内部存在一个基于多播模型的队列,如果队列不为空,则逐个取出且执行(部分浏览器中不会按序取出),如果为空则跳过,因此编码者能做的最多就是向第二种“稀释”状态迁移。
第二种,就像题主你提到的,第一次执行时移除事件绑定,然后设定一个延迟函数再次绑定事件,假设一个10秒的时间内,每间隔1s执行一次滚动,延迟函数为5s,那么在整个过程中,触发onscroll的次数为10次,而触发回调为2次。
第三种,则是诸位提到过的函数节流,基本上就是用warp函数包裹具体的业务函数,由warp函数控制具体的业务函数执行次数,因此沿用上一种状态提到的流程,假设节流的delay/wait time是5s,整个过程中,触发onscroll次数为10次,触发回调10次,具体执行定义的业务逻辑为2次。
所以,面试时问这种语义不清的名词,叫人怎么回答呢....
稀释的意思是让scroll的事件处理器执行次数减少,以降低浏览器性能消耗。Underscore.js里有2个比较相似的方法,一个是函数节流,.debounce(function, wait, [immediate]) ,即若第一个函数参数下一次执行与上次执行在固定时间wait间隔内的话就不会执行,这种状态一直持续下去直到事件不再触发则执行最后一次;还有一种是固定时间间隔的执行函数,.throttle(function, wait, [options]) ,类似于setInterval()。按照面试官的意思应该是用第二种。
用一个变量记录上次执行的时间不就行了?
请参考这两篇文章~
实例解析防抖动(Debouncing)和节流阀(Throttling)
【前端性能】高性能滚动 scroll 及页面渲染优化
里面讲到了'稀疏'滚动事件的两种办法:
(注意浏览器DOM触发的滚动事件本身, 是没有办法稀疏的, 我们能稀疏的只有被触发事件内部的事件处理函数)
debounce, 将触发频繁的函数合并, 并延迟触发throttle, 也是合并触发频繁的事件, 但并不延迟, 而是保证至少间隔一定时间触发.requestAnimationFrame, 相当于2.的间隔时间 == 16ms的版本. 能保证60fps.第一篇文章主要是这三种方法使用
underscore和lodash库的实现, 第一篇文章则是原生JS实现.