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

11月14日更新:前端

首先謝謝你們對這個問題的討論,爲了後來的童鞋方便瀏覽,我結合你們的論文,從新補充編輯此貼,爲標藍色加粗字體部分。面試

 

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

 

問題大意: 若是點擊一個按鈕發送異步請求,如何防止短期內用戶重複提交,從而形成數據覆蓋等問題:後端

我回答的解決方法有:服務器

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

 (11月14號更新: dom

提交後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函數,再次感謝。

 

固然不知道面試官但願我能回答出來的更好方法是什麼,因此請有看到的朋友能不吝賜教,謝謝。

相關文章
相關標籤/搜索