为啥题目这样写,因为之前绑定滚动调试事件我是这样写的:
element.addEventListener('scroll', function() {
// do something
})
想过要优化这个,因为滚动事件,会触发很多次,里面的逻辑过于复杂,那么会很占用浏览器资源。但是不知道从何优化。
直到看到《JS高程》的函数节流,滚动条和事件和resize操作,是同样的道理,实际上我们需要做的操作只需要在滚动条事件完成或者resize的操作完成的一瞬间去执行我们的逻辑,中间的过程,我们的逻辑处理是没有意义的,因为它只是一个中间状态。
定义这样一个对象:
var processor = {
timeoutId: null,
//实际执行的代码
performProcessing: function(){
console.log('performProcessing 方法, 你的处理逻辑')
console.log('hello word')
},
//初始处理调用的方法
process: function() {
console.log('process方法')
clearTimeout(this.timeoutId)
var that = this
this.timeoutId = setTimeout(function(){
that.performProcessing()
}, 100)
}
}
我们在绑定滚动条事件可以这样:
window.onscroll = function(){
processor.process()
}
《JS高程3》上面用的是throttle节流来命名方法解决,但是按照lodash 和underscore 都是用的debounce防抖来解决这个问题。我们不纠结这个问题。先看《JS高程3》最后的封装方法
function throttle(method, context) {
clearTimeout(method.tId);
method.tId = setTimeout(function () { method.call(context); }, 100);
}
我们绑定一个滚动条滚动事件,并且指定我们的处理逻辑->print函数:
function print() { console.log('scroll handle logic') }
window.onscroll = function() { throttle(print) }
好到了这一步,我们已经能够解决类似的问题了,像scroll 和 resize事件的话,这类事件,实际上我们只需要最后一次去触发,不然我们scroll事件触发了100次,每次都得触发是不行的,只需要最后一次去触发。上面的函数实际上是利用定时器,比如我们1s之内连续触发了100次,我们每执行到throttle函数回去检查,print方法的tId是否存在,也就是上一个定时器是否存在,如果存在,则清除,连续的过程中,只要100ms内的连续操作,前面的定时器是被取消了的,最后一次没有被取消,在最后一次的事件触发的100ms之后会触发。(O__O …,大概就是这样,希望没搞晕你)
throttle 节流 和 debounce 防抖
lodash 和 underscore给我们提供了这些方法的扩展,并且有更多功能。
在resize 和 scroll 以及 ,防止用户重复点击提交数据,检查用户输入的数据(ajax请求) 都可以用到debounce防抖,这些操作只需要最后一次(或者第一次)的事件被触发。
在检测用户是否要滑动到页面底部(加载更多数据),这种情况需要用到throttle 节流,每隔多少时间去触发事件。
权威参考:
https://css-tricks.com/debouncing-throttling-explained-examples/
example(in vue):
比如有一个input,我们的需求是将用户输入的英文字母变成大写的,代码长下面这样,
function里面的实际上可以换成请求服务器,检查名字是否重复等操作。
<input type="button" v-model="name" @keyUp="upperName"/>
import { debounce } from 'lodash'
export default {
data () {
return {
name: ''
}
},
methods: {
upperName: debounce(function(){
if(isString(this.name)) { this.name = this.name.toUpperCase() }
}, 100),
}
}