js防抖节流新姿势
2019-03-20 本文已影响0人
fyAgent
什么是防抖节流
为了防止某个特定的函数(尤其是内部有异步操作)在未得到结果前被重复执行,或者想要用户输入、页面滚动等行为所对应的函数不那么频繁的被触发而使用的限制操作称为防抖节流。
let isPending=false;//--
async function throttle(){
if(isPending) return;//--
isPending=true;//--
try{//--
await new Promise(resolve=>{
setTimeout(_=>{
resolve();//或者reject
},3000)
})
}catch(err){
//do nothing
};
isPending=false;//--
}
但是这样仍然比较麻烦,因为我们大部分情况下写了一堆额外的代码只是为了让开关正常归位。
不过最近在写egg+vue+ts服务端渲染的时候使用了基于类的api开发方式,虽然感觉vuex结合ts并不太甜但是感觉ts还是真香,vue 的class写法虽然让我们丧失了mapState这样非常方便的操作但同时解锁了新的黑科技--decorator(装饰器),下面我们使用装饰器来实现一个非侵入式的节流功能;
/**
* @param {number} deylay当函数执行完后再次执行的时间间隔
*/
function Throttle(deylay: number = 0): Function {
let isPending: boolean = false;
return (target: any, name: string, descriptor: any) => {
var oldValue = descriptor.value;
//重写函数
descriptor.value = async function (...args: any[]) {
if (isPending) return;
isPending = true;
try {
await oldValue.apply(this, args);
} catch (err) {
//do nothing
};
if (!deylay) return isPending = false;
setTimeout(() => {
isPending = false;
}, deylay);
};
return descriptor;
};
};
//测试
class Test {
@Throttle()
public async fn():Promise<void>{
console.log("fn 执行了");
await new Promise(resolve => {
setTimeout(()=> {
resolve();
}, 3000);
});
};
};
const test = new Test();
setInterval(test.fn,50);
利用类似的思路我们同样可以实现请求耗时、日志等很多功能:
//经测试会有毫秒级的误差
function TimeCost(target, name, descriptor) {
var oldValue = descriptor.value;
descriptor.value = async function (...args) {
const timeStart = new Date().getTime()
try {
await oldValue.apply(this, args);
} catch (err) {
//
};
console.log(`function:[${name}] costs: ${new Date().getTime() - timeStart}ms`);
};
return descriptor;
};