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函數,讓傳入函數只執行一次


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM