首頁 > JavaScript > [JavaScript] 五分鐘小教室 – 不重複送出 Ajax Request

[JavaScript] 五分鐘小教室 – 不重複送出 Ajax Request

2008年8月2日 jaceju 發表評論 閱讀評論

這次在設計購物車時,遇到了以下的介面:

客戶的需求是在按下「 + 」 或「 – 」時,要以 Ajax 發送更新的數量到後端系統去驗算;每按一次「 + 」 或「 – 」,就要送出一次 Ajax Request。

可是這時候問題就來啦,如果數量要 10 個的話就要連續按 10 次「 + 」,也會連續發送 10 次的 Ajax Request ;這樣不但會浪費珍貴的網路頻寬,更不用說會造成後端系統的負擔。

怎麼解決呢?其實方法很多,而這裡我採用最簡單的 setTimeout 和 clearTimeout 。程式如下:

var sending = null;
 
var _formSubmit = function () {
    alert('Form submited!');
};
 
var _doAjaxPost = function () {
    if (sending !== null) {
        clearTimeout(sending);
        sending = null;
    }
    sending = setTimeout(_formSubmit, 1000);
};
 
var plusQuantity = function () {
    // ... 執行增加數量的動作 ...
    _doAjaxPost();
    return false;
};
 
var minusQuantity = function () {
    // ... 執行減少數量的動作 ...
    _doAjaxPost();
    return false;
};
 
$(function () {
    // 增加數量
    $('a.plus').click(plusQuantity);
 
    // 減少數量
    $('a.minus').click(minusQuantity);
});

註:這裡我大量使用了 jQuery 的功能。

想法很簡單,就是當我們按下「 + 」 或「 – 」時,要隔一秒才會送出 Ajax Request ;而在這一秒內如果再次按下「 + 」 或「 – 」,那麼就重新計時。

因此程式的主要重點在 _doAjaxPost 這個函式以及全域變數: sending ;當第一次呼叫 _doAjaxPost 時 sending 還是 null ,這時我們利用 setTimeout 開始計時,並將計時器指定給 sending 這個變數。而當第二次呼叫時, sending 變數已經不為空值,因此我們再利用 clearTimeout 將它清除,並重設為 null 以達到重新計時的目的。

是不是很簡單呢?

如果各位有更好的作法,也歡迎分享~

Categories: JavaScript Tags:
  1. 2008年8月3日14:19 | #1

    是要驗算數量乘以單價的總價嗎?可不可以把單價echo到另一個文字框,然後直接在前端相乘呢?

  2. jaceju
    2008年8月3日14:32 | #2

    @yoren:

    其實這裡在後端做的事遠比驗算複雜很多,只是因為我的重點不是驗算這件事,所以我略過很多細節。

  3. hermes
    2008年8月4日00:11 | #3

    Dear Jace:
    我是這樣做的:當圖片 onclick 時就先 _doAjaxPost(),然後再 unbind _doAjaxPost(),這樣的話,一直按下click 就會沒有用處 ,然後在接收 post 的那支 php 內使用 sleep(1) 的函式,這樣就會呆住一秒,然後在 js 收到 response 時,圖片再去 bind _doAjaxPost()。

    大致上是這樣 ^^

  4. sy
    2008年8月4日01:43 | #4

    Hi hermest.
    你如果 unbind _doAjaxPost() 的話
    後端實在沒有必要再做 sleep 了
    讓 client 收到 response 時 enable button 就夠了

    Hi jaceju,
    不過這篇的目的是否少解釋了使用者連續按的處理
    應該是(在一秒內)連續按 n 下, 會先送一次+1, 後面n-1次會 queue 住, 等一秒後再送一次 n-1
    否則如果使用者真的要買 10 個, 就要花十秒鐘, 這樣的設計是不合理的

  5. hermes
    2008年8月4日09:40 | #5

    Dear sy:
    之所以會使用 sleep,主要的目的是在要求使用者 click 的間格必須要為一秒鐘。當然,之所以會這樣設計,主要是因為我是利用 db 來記錄 cart 內的商品資訊的緣故

    不過您說的也沒有錯,某些情況底下若有利用 sleep 去限制使用者的 click 間格的確是不合理的 ^^

  6. jaceju
    2008年8月4日09:50 | #6

    @sy:

    耶?我應該一開始就有說是為了解決連續按的問題吧?還是你試過會 hang 住十秒?整個程式只有最後一次的 Request 會被送出,也是在一秒鐘後送出的。

    目前程式運作還滿正常的,不曉得我哪裡有解釋不清的呢?請指教囉~

  7. sy
    2008年8月4日11:37 | #7

    @jaceyu:

    我又重新看一次你的文章,才確定你的方法
    你的方法是將使用者按的次數累積下來
    直到按完之後(間隔超過一秒)才將總數一次送出, 是嗎?
    那這樣應該沒什麼問題, 只是程式對於使用者的操作不是立即反應, 不過這問題不大

    我原本是想成你限制每個 ajax request 必須間隔超過一秒,然後又是一個 request 代表 +1 的動作, 這樣下來如果要 +10, 就必須每隔一秒按一次, 整個流程必須花十秒.

    我建議這個例子可以改成
    var _formSubmit = function () {
    alert(‘Form submited! (‘+count+’)');
    count = 0;
    };

    並且在 plusQuantity()跟minusQuantity() 作 coun++ 及 count–
    這樣會比較清楚..

  8. jaceju
    2008年8月4日11:42 | #8

    @sy:

    哈!果然是例子的問題。因為我實在沒空想一下好範例,又不能直接拿線上實例來用 (很複雜) ,所以就簡單寫一下囉。

    這邊有空我再改吧,被鬼抓去勞改中。

  9. 2008年8月4日11:55 | #9

    我是覺得,你一定要用+-這種介面嗎?
    何不限制每張訂單中每項商品的訂購上限,比如說10個,用下拉式選單就解決了~
    或者讓使用者自己填入數字也可以…

  10. jaceju
    2008年8月4日12:16 | #10

    @tokimeki:

    簡單來說就是政治因素 ^^|||

    而且就算是用下拉選單,也還是會遇到同樣的問題;因為有時候我們點選下拉選單後,不小心碰到滑鼠滾輪時,也會有連續同時送出 Request 的問題。

    不過這裡政治因素的問題比較大,所以…

Spam Protection by WP-SpamFree