性能优化的知识
共同点:降频( 降低函数的调用 )
场景:
一个功能本身就是要限制被调用的次数。例如用户请求登陆的次数不能太频繁。
一个功能没有必须被频繁调用。
防抖(debounce)
某个时间内不能再次触发,一旦触发,就要重新计时。在这个时间内没有被再次调用,才会真正的执行,
如果一直按,就会一直重新计时
防抖函数分为非立即执行版和立即执行版
简单写法:
hInput () {
clearTimeout(this.timer)
console.log(this.keyword)
this.timer = setTimeout(() => {
this.doAjax()
}, 200)
},
doAjax () {
xxxx
},
立即执行
点击按钮,函数f1调用后,立即执行f()。随后,每次点击都不会调用f(),并且会从新开始计时
<button id="btn_debounce_now">防抖3s,立即执行</button>
<script>
function debounce_callnow(f, t = 3000) {
var time = null
return function () {
if (!time) {
//如果time是空的话,就直接执行
f()
} else {
console.log('不要着急,等3s后再点才有效')
}
clearTimeout(time)
//每次点击后,过三秒钟才会清一次time
time = setTimeout(() => {
time = null //清空time
}, t)
}
}
function f() {
console.log(Date.now())
}
var f1 = debounce_callnow(f)
document.getElementById('btn_debounce_now').onclick = f1
</script>
非立即执行版本
以下代码每次点击完要等一秒才能看到结果,在一秒以内每次点击都会从新开启定时器
<button type="primary" id="btn_debounce_end">防抖1s,延迟执行</button>
<script>
function debounce_end(f, t = 1000) {
let time = null
return () => {
if (time) {
//如果存在time 就会清空定时器,从新开始
clearTimeout(time)
console.log('1s以后看结果')
}
time = setTimeout(() => {
f()
}, t)
}
}
function f() {
console.log(Date.now())
}
var f1 = debounce_end(f)
document.getElementById('btn_debounce_end').onclick = f1
</script>
混合版本
在立即执行版本的基础上,定时器结束以后再执行一次f()
<button id="btn_debounce_now">防抖3s,立即执行</button>
<script>
var time = null
function debounce_callnow(f, t = 3000) {
return function () {
if (!time) {
//如果time是空的话,就直接执行
f()
} else {
console.log('不要着急,等3s后再点才有效')
}
clearTimeout(time)
//每次点击后,过三秒钟才会清一次time
time = setTimeout(() => {
time = null //清空time
f() //t秒以后再执行一次
}, t)
}
}
function f() {
console.log(Date.now())
}
var f1 = debounce_callnow(f)
document.getElementById('btn_debounce_now').onclick = f1
</script>
节流 (throttle)
限制 函数两次调用的时间间隔,他们的时间间隔是固定的 ;比如间隔3秒钟才能执行,那么这三秒内不管触发了多少次该事件,函数都只执行一次
简单写法:
data() {
return {
timer: null,
startTime: 0, // 最近一次成功调用ajax的时间
}
},
hInput {
const dt = Date.now()
if (dt - this.startTime > 500) {
this.doAjax()
this.startTime = dt
} else {
console.log('当前的时间戳是', dt, '距离上一次执行不够500ms,所以不执行')
}
},
doAjax()
}
中级写法:
立即执行版 ——>点击按钮时,会立即执行f ,但是不论点的有多块,都间隔1s执行一次
<button id="btn_throttle_now">节流1s,立即执行</button>
<script>
var time = 0
function throttle_now(f, t = 1000) {
return () => {
var now = Date.now() //获取当前时间戳
if (now - time >= t) {
// 如果间隔时间大于t,就可以执行f
f()
time = Date.now()
} else {
console.log('必须超过1秒')
}
}
}
function f() {
console.log(Date.now())
}
var f1 = throttle_now(f)
document.getElementById('btn_throttle_now').onclick = f1
</script>
非立即执行版 ——>点击按钮时,等一秒以后会执行一次f;但后续不论点的有多块,都间隔1s执行一次
<button id="btn_throttle_end">节流1s,延迟执行</button>
<script>
function throttle_end(f, t = 1000) {
let time = null
return () => {
if (!time) {//如果time不是null,就不能执行f
time = setTimeout(() => { //每间隔1s,将time设置为null
f()
time = null
}, t)
} else {
console.log('请等一秒钟')
}
}
}
function f() {
console.log(Date.now())
}
var f1 = throttle_end(f)
document.getElementById('btn_throttle_end').onclick = f1
</script>
混合版
第一次点击按钮,会立即执行f。如果在3s内再次点击,则会开启一个三秒后执行的定时器。
<button id="btn_throttle_now">节流3s,立即执行</button>
<script>
function throttle_callnow(f, t = 3000) {
let timer = null
let preTime = 0
return function () {
var now = Date.now()
clearTimeout(timer) //如果3s内再次点击,就会先清除上一次点击的定时器
if (now - preTime >= t) {
f() //立即先执行一次
preTime = now
} else {
console.log('间隔不足,开始定时器')
// 如果间隔不足,才会开启这个定时器
timer = setTimeout(() => {
f() //如果三秒内没有再次点击,就会执行f。如果再次点击,就会清除这个定时器
}, t)
}
}
}
function f() {
console.log(Date.now())
}
var f1 = throttle_callnow(f)
document.getElementById('btn_throttle_now').onclick = f1
</script>