2016-06-09 41 views
2

我有一個關於回調函數的問題,它位於$(document).ready。回調函數沒有用於工作。當我把它放在$(document).ready之外時,代碼已經開始完美工作。我不明白爲什麼。位置很重要?Ajax回調函數的位置

這工作:

$(document).ready(function() { 
    $("#button1").click(function() { 
    $.ajax({ 
     url: "http://www.example.com/data.php", 
     type: "get", 
     dataType: "jsonp", 
     jsonpCallback: "read", 
    }); 
    }); 
}); 
var read = function(data) { 
    console.log(data); 
} 

這是行不通的。

$(document).ready(function() { 
    $("#button1").click(function() { 
    $.ajax({ 
     url: "http://www.example.com/data.php", 
     type: "get", 
     dataType: "jsonp", 
     jsonpCallback: "read", 
    }); 
    }); 
    var read = function(data) { 
    console.log(data); 
    } 
}); 

UPDATE1:對不起球員,鏈接werent't不同。我忘了改變第二個。閱讀功能的位置只有一個區別。

+0

了不同的網址。第二個域是否支持跨域請求? –

+0

[爲什麼我不能在jQuery的document.ready()中定義函數?](http://stackoverflow.com/questions/1055767/why-can-i-not-define-functions-in-jquerys-document -ready) –

回答

0

$(document).ready(function() {表示:當頁面加載完成時執行此操作。 在第二個示例中,僅在頁面加載完成後才能定義read函數。

在工作示例,您首先定義read功能,並說,「一旦該頁面將被加載,執行AJAX調用,然後,調用read功能」

編輯:此外,您還可以閱讀@ IGeoorge回答更詳細的解釋。

+0

實際上並不是在定義函數和ajax調用完成之間存在競爭條件的情況。因爲它是JsonP請求,所以回調*必須*存在於全局範圍('window')中,或者執行的JsonP腳本不會找到該函數。 – Chev

-1

添加讀取方法阿賈克斯之前

$(document).ready(function() { 
    var read = function(data) { 
    console.log(data); 
    } 
    $("#ara-button").click(function() { 
    $.ajax({ 
     url: "http://www.csstr.com/data.json", 
     type: "get", 
     dataType: "jsonp", 
     jsonpCallback: "read", 
    }); 
    }); 

}); 
+0

這仍然行不通。 JsonP請求需要回調函數存在於全局範圍內。 – Chev

-1

你的函數定義爲jQuery的範圍,所以在目前執行AJAX,找不到的「讀」的功能定義。

這就是第一個例子工作的原因。

希望這會有所幫助。

4

您將JsonP回調名稱作爲字符串傳遞的原因是因爲JQuery需要將它添加到您的URL中,如?callback=read。 JsonP請求只是由JQuery在後臺創建的<script>標記,並添加到頁面<script src="http://www.csstr.com/data.json?callback=read"></script>。一旦JQuery將腳本標記添加到頁面中,瀏覽器就會像處理正在加載的普通JavaScript文檔那樣對待它。由於請求的?callback=read部分,遠程服務器知道要使用可執行的JavaScript進行響應,而不僅僅是原始數據。這個可執行的JavaScript只是一個函數調用,它提供了你提供的名字,在這種情況下是read函數。由於返回的腳本正在全局範圍內執行,因此全局範圍中也需要存在該功能。瀏覽器中的全局範圍是window對象,因此基本上read函數需要存在於window對象中,以便執行的腳本能夠找到該函數。

$(document).ready(function() { 
    $("#ara-button").click(function() { 
    $.ajax({ 
     url: "http://www.csstr.com/data.json", 
     type: "get", 
     dataType: "jsonp", 
     jsonpCallback: "read", 
    }); 
    }); 
    window.read = function(data) { 
    console.log(data); 
    } 
}); 

它在第一個示例中的ready函數之外工作,因爲在根級別定義的任何東西都是全局作用域。

Codpen演示:http://codepen.io/anon/pen/qNbRQw


如果您想了解更多關於JSONP是如何工作的,請繼續閱讀。

如果您仍然感到困惑,那可能是因爲您對JsonP的實際工作原理並不十分熟悉。 JsonP是一個破解Same-origin Policy。同源策略的簡短版本是瀏覽器不會讓你讀取從請求返回的請求返回的請求,除非請求源發出的請求來自域名服務器,除非該域名的服務器認爲它沒問題。

大多數瀏覽器都實施了同源策略,以幫助保護用戶免受惡意腳本攻擊。例如,如果您在一個瀏覽器標籤中通過銀行網站進行了身份驗證,然後在另一個標籤中訪問惡意網站,則瀏覽器中沒有同源限制,惡意網站可能會向您的銀行網站發送ajax請求。該請求會攜帶您的瀏覽器爲該域存儲的任何Cookie,並且您的Cookie會將您顯示爲已驗證身份,從而使攻擊腳本可以從您的銀行帳戶訪問已驗證的數據。同源策略可防止惡意網站查看來自該請求的響應數據。

在開始時,客戶端和服務器沒有正式的方式來選擇跨域共享。當時它只是被瀏覽器擋住了。爲了避開這個JsonP被髮明瞭。同源策略只隱藏了來自ajax請求的響應,但您可能已經注意到瀏覽器通過<script>標籤從其他網站加載腳本完全正常。腳本標記只是爲javascript文檔做一個普通的舊GET請求,然後開始在頁面上執行該腳本。 JsonP利用了這一事實,即同源限制不適用於<script>標籤。

請注意,如果您在瀏覽器中直接轉到http://www.csstr.com/data.json,您會看到您所查看的數據。但是,嘗試去那裏添加以下查詢字符串。

http://www.csstr.com/data.json?callback=read

注意到有什麼不同?而不是僅僅返回您想要的數據,而是將您的數據傳遞給名爲read的函數。這就是你知道服務器如何理解JsonP黑客。它知道要在函數調用中包裝所需的數據,以便JQuery可以在客戶端上執行JsonP破解,通過創建<script>標記並將其嵌入到網頁中來實現。該腳本標記指向該URL,但也添加了查詢字符串到它的末尾。結果是一個腳本標記,從該URL加載腳本並執行它。該腳本正在加載到頁面的全局範圍中,所以當調用read函數時,它期望該函數也存在於全局範圍中。

今天,圍繞同源政策的官方方式是通過跨源資源共享策略(又名CORS)。 JsonP基本上完成了與CORS請求相同的事情。服務器必須知道如何將響應格式化爲可執行的JavaScript,並且客戶端必須知道不要執行正常的ajax請求,而是動態地創建腳本標記並將其嵌入到頁面主體中。然而,JsonP仍然是一個黑客,而黑客也有它自己的缺點。 JsonP真的很難調試,因爲處理錯誤幾乎是不可能的。如果請求因爲通過<script>標記發出請求而失敗,則無法輕鬆捕獲錯誤。 <script>標籤也無法控制請求的格式;它只能發出普通的GET請求。 JsonP最大的缺點是需要創建一個全局函數來用作數據回調。沒有人喜歡污染全局名稱空間,但是JsonP需要它才能工作。

正確的CORS請求不需要客戶端的額外努力。瀏覽器知道如何詢問服務器是否允許讀取數據。服務器只需響應正確的CORS頭文件就可以了,然後瀏覽器將解除相同的原始限制,並允許您像該域一樣正常使用ajax。但是有時你試圖打的資源只知道JsonP,並且不會返回正確的CORS頭文件,所以你必須回退它。

欲瞭解更多關於CORS的信息,我剛纔寫了一個非常詳細的blog post,應該真的幫助你理解它。如果你控制返回你之後的數據的服務器,那麼你應該考慮讓它返回適當的CORS頭並忘記JsonP。但是當你不控制服務器並且不能配置它返回正確的頭部時,這是完全可以理解的。有時候,JsonP是獲得所需內容的唯一方式,即使它會讓你在編寫代碼時嘔吐一下。

希望幫助清楚一些事情爲你:)

+1

完美的解釋!謝謝@Chev – u238

+1

沒問題:)不要忘了點擊接受按鈕來驗證我是一個人:P – Chev

+1

:'(現在我永遠不會有信心我需要開心。 – Chev