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

一、情景需求

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

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

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

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

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

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

二、实现

1.函数重写

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

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

2.通过变量控制

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

let value = true;
function fn(){
    if(value){
        //do something
        console.log(1);
        //执行一次后将变量改为false
        value = false;
    };
};
fn();//1
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); //3
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();//1
o();//1

三、小总结

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

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

那么本文到此结束。

四、参考

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

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

原文地址:https://www.cnblogs.com/echolun/p/11123905.html