一道面試題:如何防止異步請求的重復提交


11月14日更新:

首先謝謝大家對這個問題的討論,為了后來的童鞋方便瀏覽,我結合大家的論文,重新補充編輯此貼,為標藍色加粗字體部分。

 

今天面試時考官問了一道題,以下是大致的回憶:

 

問題大意: 如果點擊一個按鈕發送異步請求,如何防止短時間內用戶重復提交,從而造成數據覆蓋等問題:

我回答的解決方法有:

1. 提交后disable掉按鈕,再次點擊文本框時enable按鈕

 (11月14號更新:

提交后disable按鈕是常用方法,

外觀表現上有:1. disable 按鈕,在按鈕上顯示提交中等信息

                     2. 設置遮罩層,遮罩層上顯示提交信息。

 

在代碼處理邏輯上是:

                     第一步: 設置開關變量。

       第二步: 提交前關掉按鈕

                     第三步: 在回調函數中打開按鈕

                   

var isQuery = false;
function query() {
    if (!isQuery) {
        $.ajax({
            beforeSend: function() {
                isQuery = true
            },
            success: function() {
                isQuery = false
            },
            error: function() {
                isQuery = false;
                return;
            }
        })
    } else {
        alert("waiting!!!");
    }
}

 

 

 

以下一段文字僅是補充當時的場景,disable 按鈕的方式看上面代碼即可,以下可忽略  : )

上文中 ”再次點擊文本框時enable 按鈕使“ 不是disable 方法的一部分,只是為了補充 用開關變量disable按鈕的思路可能存在一個問題:如果服務器端處理時間很長,甚至是服務器端掛掉了,一直在等超時的期間客戶沒法再次輸入,因此設置了 再次點擊文本框時enable 按鈕 )

 

面試官追問,那么如果用戶還是快速地點擊文本框,還是能快速地提交,

 

2. 我想到了設置一個緩沖時間,例如200ms,200ms內的重復請求忽略,只執行最后一次的請求。

這個方法的代碼:

var timer = null;
btn.addEventListener('click', function () {
    if (typeof timer === 'number') {
        clearTimeout(timer);
    }
    timer = setTimeout(function () {
        //添加提交按鈕的事件處理
    }, 200);
}, false);

 

我說這會影響到所有的用戶的每次請求都有延遲,然后繼續想:

 

3. 所以想到提交后disable,然后settimeinterval,每隔一定時間,例如一秒鍾,如果是disable的話那么enable 

( 其實這是在嘗試解決上面提到的如果服務器端處理時間特別長,用戶想重新輸入的問題。

PS: 因為是面試,我這里是為復述整個故事,其他童鞋可以忽略這段 )

面試官指出,那么這個計時器就一直需要在運行咯,是啊,這樣也是在消耗, (正在寫博客的時候我在想能否設置一個計數器,如果連續好幾次都是disable狀態的話,可以移除定時器)

 

於是繼續想:

4. 我想對每個異步請求判斷下IP,如果是短時間內快速的重復提交,設定一個閾值,超過則判斷為spam,把ip地址ban掉或者忽略請求,但這個缺陷是對每一個請求都進行了額外操作。

然后面試官說這要后端配合,如果是前端呢?

5. 我想到了設置hash值,發異步請求時帶上一個hash值,如果服務器端在處理上一個請求還沒有完成時又來了新請求,那么可以丟棄,繼續等待返回,這樣不會覆蓋數據。

然后發現,有走到需要后端配合了,面試官繼續問,如果不要后端配合,如果僅僅是前端怎么做,

6. 我只好想到發送異步請求時候帶上時間戳/hash值,返回數據的時候也帶上時間戳/hash值,然后看是不是最近發送的那個請求,是則渲染,否則丟棄。

 

但是面試官在問有沒有更好的方法,

我當時如實告訴面試官想不出來了,很抱歉,

 

剛才我看了下 xhr 對象的 API,發現有 abort() 方法,能立即取消請求,這個當然方便,每次保留上一次提交的xhr對象引用,下次點擊時先abort() 上一個xhr請求,再重新發送請求,但是當時不知道這個方法,其實自己有想到是不是 xhr對象直接有取消請求的方法,但轉而一想面試不可能這么簡單吧,然后我不確定這個方法是否存在。所以沒回答這個方法。

(abort()  方法取消當前響應,關閉連接並且結束任何未決的網絡活動。

這個方法把 XMLHttpRequest 對象重置為 readyState 為 0 的狀態,並且取消所有未決的網絡活動。例如,如果請求用了太長時間,而且響應不再必要的時候,可以調用這個方法。請見: http://www.w3school.com.cn/xmldom/dom_http.asp

)

11月20日更新:感謝面試官,雖然面試掛了,還能有機會再次溝通,得知 abort()方法其實是當時面試官心里期待的回答,那個滾動條優化,面試官期待的是 throttle函數,再次感謝。

 

當然不知道面試官希望我能回答出來的更好方法是什么,所以請有看到的朋友能不吝賜教,謝謝。

 


免責聲明!

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



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