javascript筆記:對ajax回調函數的研究

  這篇博文是我針對項目組開發中遇到的問題研究,今天已經和同事們進行了分享,這裏把它貼到我的博客裏,和廣大博友交流,希望能在和大家交流中自己得到進一步的提高。

  和同事交流的文檔的標題是:關於javascript的回調函數及ajax回調函數研究

  具體內容如下:

1.1開發中遇到的問題

  最近開發中我和同事都碰到這樣的問題,我們使用jQuery的ajax方法做服務端的校驗,在success方法裏將驗證結果存儲到一個js的公共變量或者是頁面裏的隱藏域,接下來的代碼我們會根據這個公共的js變量或者是這個隱藏域裏的值判斷下一步的操作,但是這樣做的結果很讓人失望,我們發現js公共變量的值或者是隱藏域的值並沒有改變,從而導致我們下面的代碼無法正常運行。下面我模擬這個問題產生的代碼,代碼如下:

  callback.js:

View Code

  java程序:

public String studyCallBack() throws Exception{
        this.vflag = "true";
        this.vmsg = "Number:9999999";
        return "validateServerBack";
}

  Struts的配置文件:

複製代碼
    <package name="vumssmer" extends="json-default" namespace="/vumssmer">
        <action name="vmerservice" class="com.unionpay.mim.web.action.UMSSMerManageAction">
            <result name="validateServerBack" type="json">
                <param name="includeProperties">vmsg,vflag</param>
            </result>
        </action>
    </package>
複製代碼

【注意:console.log方法只有在firebug裏使用纔有效】

執行結果是,如圖1-1:

 

            圖1-1

服務端我設定的返回值vflag:true,vmsg:Number:9999999,success方法打印的結果是正確,但是接下來的代碼卻執行錯誤了。

以上就是我們在開發過程中遇到的問題,下面我會從這個現象一步步研究,希望最終的結論與正確的答案一致。

1.2研究“開發中遇到問題”的過程

我首先把btn01的click事件拆分爲兩個獨立的按鈕事件,大家看callback.jsp的代碼:

View Code

 

頁面的效果是,如圖2-1:

                圖2-1

我們先點擊BUTTON2按鈕,再點擊BUTTON3按鈕,結果如下,如圖2-2:

        圖2-2

這時的結果是正確的。
這到底是怎麼回事了???
我們仔細看看兩次代碼的區別了,btn01的代碼都在一個函數裏,而btn02和btn03的代碼分屬在不同的function裏,我們再看看圖1-1裏顯示的結果,打印出來的結果並沒有按照代碼的順序,if裏的打印代碼先打印,而ajax的success方法裏的代碼後打印的。這說明如果代碼在一個function裏,if代碼會先於success裏的代碼被執行,代碼並不是按我們書寫代碼的順序執行的。

對ajax熟悉的人都應該知道,我們處理ajax請求回來的結果都要定義一個回調函數,那麼產生上面現象是不是因爲回調函數都會在包含它的函數裏滯後執行了。爲了解開這個疑問,我做了如下的測試,大家看下面的callback.jsp代碼:

View Code

執行的結果如下:

      圖2-3

執行的結果是函數是按代碼順序執行。這和jQuery的ajax執行結果不同,那是不是因爲jQuery代碼的寫法所導致的呢? jQuery代碼是通過匿名函數設計的,裏面的jQuery對象是按照json的格式定義的,如是我把代碼更改成這樣的,代碼如下:

View Code

執行結果如下,如圖2-4:

            圖2-4

結果是按代碼書寫順序執行的,看來不是javascript回調函數引起的上面的問題。
如果不是回調函數那麼就應該是ajax本身了。
這裏我還是按照jQuery的結構來寫實例代碼,ajax使用原生態的方式編寫,這樣會讓我們探討的問題更加清晰,代碼如下:

View Code

結果如圖2-5所示:

            圖2-6

這個結果就和我們調用jQuery的ajax方法的結果一樣了。
我的研究過程就是這樣了,下面就是我的分析結果了。

1.3我的分析結果

首先我要講講javascript裏回調函數到底是怎麼回事。回調函數在編程語言裏很普遍,java裏面也有,百度百科裏有對回調函數的定義:

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作爲參數傳遞給另一個函數,當這個指針被用爲調用它所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。

詳情可以參見:

http://baike.baidu.com/view/414773.htm

我們這裏不講回調函數實際運用的場景,從編碼角度,回調函數和調用回調函數的函數是一個統一的整體,他們在執行上是按照代碼編寫的順序至上而下的。
我在學習ajax時候,我看的書籍上都寫到onreadystatechange要賦一個回調函數,那麼按照上面的結論我們在“開發問題中”寫的代碼應該能正常運行,但是結果卻恰恰相反。
難道ajax的onreadystatechange存儲的不是我們通常理解的回調函數嗎?或者是ajax有自己特別的回調機制嗎?

我的回答是onreadystatechange存儲的是回調函數也沒有什麼特別的回調機制,但它不是被執行在我們所寫的調用ajax方法內的回調函數,而是瀏覽器執行XMLHttpRequest請求裏面的回調函數,我們書寫的我們寫的:

this.xmlHttp.onreadystatechange = this.jsonCallBack;

只是在爲onreadystatechange做賦值操作。因此我們在執行我們自己編寫的ajax函數時候onreadystatechange存儲的函數是不會被調用的,因爲這只是一個賦值操作。
那什麼時候執行onreadystatechange存儲的回調函數呢?當我們的ajax請求被成功的返回值以後,調用到了onreadystatechange存儲的回調函數,回調函數就被執行了,這就是我們看到success函數裏的代碼會滯後於我們編寫的ajax調用方法的原因所在。
在我寫的代碼裏,ajax裏的onreadystatechange存儲回調函數我都是用xQuery.xnum、xQuery.xmlHttp調用xQuery裏的方法,而不是this,大家可以試試把代碼改成用this調用,最後firebug結果會表現爲this.xmlHttp沒有定義之類的提示,這個也反向說明了回調函數調用的時候已經脫離了原來方法而變成了一個獨立的方法,因此我們存儲的回調函數所使用的變量一定要在一個公共作用域裏,因此使用了xQuery來存儲變量。
以上的結論我們可以糾正對ajax調用幾個錯誤的理解:

1. ajax裏面的回調函數的調用機制是一種特別的機制,它與javascript普通回調函數的使用不一樣;
2. ajax回調函數的作用域和ajax調用函數作用域的不同而引起的代碼不能正常運行。

正確的理解應該是:
Ajax裏的回調函數只是我們賦值給XMLHttpRequest對象的回調函數,它的執行和我們所寫的調用ajax函數無關。
實際運用中如果我們想在執行完ajax請求後,根據請求結果執行相關的邏輯,那麼請把邏輯寫在ajax的回調函數裏,只有這樣才能讓代碼按業務邏輯正常運行。


發佈了2 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章