jQuery 學習心得筆記 (5) – Ajax (下)

不再讓「下集」拖稿了...

jQuery.ajax() 的 callback

jQuery 提供的 ajax 函式其中有 4 個 callbacks: beforeSend, complete, error, 以及 success,當一個 Ajax request 送出到完成,會依照:

beforeSend » success or error » complete

這樣的順序來呼叫你所定義的 callback 函式,也就是不管成功或者失敗,beforeSendcomplete 定義的 callbacks 都會被呼叫到,而 successerror 的 callback 則是視 Ajax request 的成敗來決定誰會被呼叫。

另外值得一提的是,jQuery 1.2 開始加入 JSONP 的支援,當你的 dataType 設成 jsonp 的時候,jQuery 的 ajax 函式會將 dataType 改為 script 並且多送一個 callback 參數到 server,然後 server 可以利用 callback 參數的值來輸出適當的 script 送回給 browser 來執行,也許這樣講很抽象,直接來看之前的例子改成 JSONP 的作法:

msg.php


然後 JavaScript 的部份改成:


function processData(data) {
$('#msg').html(data.msg);
$('#msg').fadeIn();
setTimeout(function(){
$('#msg').fadeOut();
$(e.target).attr('disabled', false);
}, 3000);
}

function showMsg(e) {
$(e.target).attr('disabled', true);
$.ajax({
url: 'msg.php',
dataType: 'jsonp',
jsonp: 'processData',
data: {gender: $('#gender').val(), name: $('#name').val(), callback: 'processData'},
error: function(xhr) {
alert('Ajax request 發生錯誤');
$(e.target).attr('disabled', false);
}
}

先看 msg.php 最後的輸出,其實是根據 callback 參數的值來決定,以這個例子而言可能就會輸出

processData({msg: 'Hello, Mr. XXX'});

所以 jQuery 會自動幫你把 dataType 設成 script 好讓 browser 認得要執行,這樣就不會去呼叫 successcomplete 的 callback ,而是去呼叫你自己定義的 callback function 。

JSONP 的應用愈來愈多,像是 Google Calendar API 或是 twitter API 都有用到 JSONP,如果想了解更深入一點,可以參考這裡

Global event

(在看這一段之前,要先認識 jQuery event 的 bind/trigger 才比較能瞭解)

當 Ajax request 產生時,如果你希望網頁上其它的元件能根據 Ajax 進行中不同的流程而做些動作的話,jQuery 已經定義好了一組 event handlers (見文件中的 ajaxXXXX)。而在 jQuery.ajax 函式中,如果 global 參數設為 true 的時候(預設就是 true),它會在 ajax 的流程中,適時去 trigger 這些 event,如果有網頁元件使用這些函式來 bind 住這些 event 的話,就會去呼叫設定的 callback function。而它 trigger 的順序為:

ajaxStart » ajaxSend » ajaxSuccess or ajaxError » ajaxComplete » ajaxStop

假設我們在按鈕旁加上一個 loading... 的圖案,預設是不顯示,但是當 ajaxStart 的時候把它打開,而在 ajaxComplete 的時候再關閉。先在按鈕後加上:



然後在 script 中幫 #loading 去 bind 必要的 event:


$(document).ready(function(e){
$('#btn').click(showMsg);
$('#loading').ajaxStart(function(e){
$(e.target).show();
});
$('#loading').ajaxComplete(function(e){
$(e.target).hide();
});
});

這樣一來,當按鈕按下後建立一個 Ajax request 後,所有 bind ajaxStart event 的元件就會去呼叫定義好的 callback,而整個 Ajax request 完成後,ajaxComplete event 又會被 trigger。

jQuery/Ajax 部份所提供的 API 真是讓我們減輕不少使用 Ajax 上的負擔,再加上自訂 ajaxXXXX event 的架構,讓你不用把所有的動作擠在同一個 callback function 之中,完全符合 jQuery 的以網頁元件為中心的理念。

如果不想每一次使用 ajax 都設定那麼多參數的話,其實 jQuery/Ajax API 還定義了一些快速的函式(如:load, post, getJSON, getScript),一樣是兩三下就完成 ajax 的動作。

  • hsiang

    你的JSONP範例跑步起來,少了jsonp: ‘processData’,

  • [quote comment=””]你的JSONP範例跑步起來,少了jsonp: ‘processData’,[/quote]
    多謝指教,已修正 🙂

  • axis

    問題回報:

    1.這個範例在IE6跑不起來

    2.在最後要重新顯示#btn的這行
    $(e.target).attr(‘disabled’, false);
    已經確定不論在IE還是FIREFOX都沒有作用
    但是改回
    $(‘#btn’).attr(‘disabled’, false);
    就都正常了

    3.我的jquery版本是 1.2.3 不知是不是有影響??

  • @axis
    感謝回報…不過我身邊沒有 IE6..所以我沒測過我自己的 sample XD
    多謝指正 m(_ _)m

  • axis

    更正一下:

    是在firefox上也跑不起來,但是稍微好一點,至少按送出後
    按鈕有被disable起來,不過之後就無任何反應

    另外我試過了jquery1.1.2版本,結果也是一樣的

  • Orz…
    這…我也不知道您跑不起來的原因是什麼 XD

  • axis

    回覆的這麼快,嚇我一跳

    再補充一下,前一個範例是正常的,
    (除了$(e.target).attr(’disabled’, false);無作用以外)
    是到這一個改用jsonp的方式就不行了

    p.s 教學寫的真好,能寫到讓新手很快入門的,也是一大學問:p

  • axis

    不好意思 又要補充 免的誤導大眾

    在FIREFOX上可以運作成功,但是在IE6上確定不行

    Orz

  • 第一個範例的 function showMsg(e) { … }
    在倒數第二行少了 “});” 所以程式會無法正常執行。

  • 請問站長:
    要如何才能觸發 jQuery 裡 “error:” 的事件?!
    因為我就算把 msg.php 從 Server 上刪除也不會發生錯誤訊息,只是一直沒結果!!

  • @Citypig
    我覺得會不會是你的 request 有 cache 住了呢?
    應該是 request 送不到(也就是回應不是 2xx)就會 error 了

  • yehchge

    這個範例中,執行到
    function processData(data) {
    …..
    $(e.target).attr(‘disabled’,false); <== e未被定義
    }, 3000);
    }
    請問要如何寫, e才有辦法定義?

  • @yehchge
    你應該要直接去拿你要作用的對象,
    而不是透過 event object 去取 target 喔

  • yehchge

    謝謝,可以了, 我改寫如下:
    function processData(data) {

    $(‘#btn’).attr(’disabled’,false); <== 這樣改寫就OK了!
    }, 3000);
    }

  • Pingback: [jQuery] AJAX 學習筆記 (一) 如何使用 JSON 驗證使用者表單 | 小惡魔 - 電腦技術 - 生活日記 - 美食介紹 - AppleBOY()

  • 1

    please could you tell me how to write JSP for the following Line:

    echo $_GET[‘callback’].”({msg: ‘$res’});”;

    I use
    out.println(callback + “({msg: Hello ” + gender+ ” ” + name + “})”);

    As a result of this, the callback function is never be called?

  • @1:
    I think that you may remove the “jsonp:’processData'”

  • azure

    您好:
    在參閱了”jQuery 學習心得筆記(4)Ajax(下)”後,最大心得是用JSONP可自行定義success之外的函數名稱,而且回傳不再是html形式。

    因此我想說回傳時能否不只回傳一筆資料,因此用您的程式改了一下,但為何永遠都只抓到一筆 ?

    while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
    $name = $row[“name”];
    echo $_GET[‘callback’].”({msg: ‘$name’});”;
    }

  • azure

    不好意思~已經弄懂了~謝^^