js函数只执行一次,函数重写,变量控制与闭包三种做法

一、情景需求

调用后台接口需要附带token信息,那么在每个请求的头部添加token的做法就不太优雅了;一个网站请求100次,那就得写添加100次token,假设某天接口有所变动,改起来就十分麻烦了。

公司项目开发使用的框架是angularjs,正好angularjs有一个请求拦截的功能;意思就是,每次请求的发起,请求拦截都能感知,所以添加token的事我们就可以在请求拦截统一处理。

为了保证请求拦截添加token永远是有效的,我在这里除了添加token,也增加了现有token的过期判断,如果token不存在,或者存在已过期,都得重新拿一次token。

结果骚操作就来,一个页面有10个请求,第一个请求触发token判断并发现已过期,就去请求新的token,巧的是请求token的接口也出了问题,并未能拿回最新token;于是第二个请求也触发了请求拦截,发现token用不了,也去请求新token,同样失败了。

js函数只执行一次,函数重写,变量控制与闭包三种做法

第三次请求拦截失败.....第四次,第五次......第十次,如果这个页面请求更多呢,永无止境了。于是,后台接口成功被我玩炸了。

js函数只执行一次,函数重写,变量控制与闭包三种做法

那么问题来了,请求拦截次数是根据请求触发的,如果token用不了,我去拿新token的操作不管成功失败,其实都只用触发一次,成功了一次搞定,失败了请求100次也都是多余。那么引出我们的问题,如果让js函数只执行一次:

二、实现

1.函数重写

我在js模式第五篇博客有提过函数重写,在这里就是十分适用了:

function fn() {
//do something...
console.log(1);
//函数重写
fn = function () {};
};
fn();//
fn();//无作为

2.通过变量控制

原理很简单,声明一个默认为true的变量,在执行一次后修改为false,通过条件判断是否需要执行:

let value = true;
function fn(){
if(value){
//do something
console.log(1);
//执行一次后将变量改为false
value = false;
};
};
fn();//
fn();//无作为

3.利用闭包

我们可以利用闭包封装一个通用函数,将你需要只执行一次的函数作为参数传入闭包,也可以达到类似的效果:

//封装执行一次通用函数
function once(fn) {
if (Object.prototype.toString.call(fn) !== "[object Function]") {
throw new Error('请传递一个函数');
}; return function (...rest) {
if (fn) {
fn.apply(this, rest);
fn = null;
};
};
}; //我们希望只执行一次的函数
function fn(a, b) {
console.log(a + b);
}; //调用闭包函数
let onlyOnce = once(fn); onlyOnce(1, 2); //
onlyOnce(); //无作为

我在网上看到了另外一种写法,原理类似,适用于一次执行的函数有返回值的情况,在第一次调用后,不管再调用几次都将跳过执行过程,直接返回第一次执行的值,也非常实用:

function once(fn) {
let can, result; if (Object.prototype.toString.call(fn) !== "[object Function]") {
throw new Error('请传递一个函数');
}; return function (...rest) {
if (can) {
return result;
}; can = true;
result = fn.apply(this, rest);
//释放fn保存的函数,便于被垃圾回收
fn = null;
return result;
};
}; function fn() {
return 1;
}; let o = once(fn);
o();//
o();//

三、小总结

我们在了解很多知识的时候,总会纳闷这个东西的使用场景在哪里,那么阅读完本文,你大概了解了如果让js中函数只执行一次的三种做法,同时也结合了我的需求,对这种用法在何时使用有了一个了解。

我在文章开头提到了angularjs的请求拦截,我发现,vue也同样有这个玩法,要不整一篇请求拦截的文章吧。

那么本文到此结束。

四、参考

让js中的函数只有一次有效调用的三种常用方法

Javascript写一个once函数,让传入函数只执行一次

上一篇:【浅层优化实战】ssh远程登录Linux卡慢的全过程排查及解决方案


下一篇:Android EditText使用详解