jQuery的 jsonp 大家應該是十分熟悉了。曾遇到過這樣的需求1、希望請求幾個相似的內容添加到頁面2、請求的內容一定時間內是固定不變的,希望做個緩存。 於是腦子一拍寫下了類似這樣的代碼 結果卻總是只有一個成功並報錯 百思不得其解,不是有一個成功了嗎?dosome怎麼就不是函數了?無奈之下花了大 ...
jQuery的 jsonp 大家應該是十分熟悉了。
曾遇到過這樣的需求
1、希望請求幾個相似的內容添加到頁面
2、請求的內容一定時間內是固定不變的,希望做個緩存。
於是腦子一拍寫下了類似這樣的代碼
for(var i = 0; i < 3; i++){ $.ajax({ url:'.../return.php?num='+i, dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'dosome', cache: true }).done(function(re){ console.log(re); }).fail(function(){ console.log('fail'); }); }
結果卻總是只有一個成功並報錯
Uncaught TypeError: dosome is not a function
百思不得其解,不是有一個成功了嗎?dosome怎麼就不是函數了?
無奈之下花了大心思和時間在localhost上研究了jQuery的jsonp原理。
設置伺服器返回如下
<?php echo 'dosome("num='.$_GET['num'].'");'; ?>
得到返回如下
仔細翻看源碼,在1.11.3版本發現
原來每次jsonp請求,jQuery都自動先把callbackName函數註冊到window,又在返回後把window[ callbackName ]改回來。
於是同步執行完for迴圈發送請求後,處理第一個返回時就把window[ callbackName ]改成了 undefined,後續的返回都無法處理了。
我一陣鬱悶,反正這個函數也沒執行什麼,不改回去不行嗎?
可惜,我還是太天真,其實不改回去也一樣無法正常得到想要的結果的。
個人理解,jQuery的jsonp原理大致如下
每次jsonp請求,都是新建一個處理函數把返回內容賦值到局部變數responseContainer,然後在調用註冊的回調函數以對應的局部變數responseContainer[0]為參數執行。
當使用不同的處理函數名時,一切相安無事(當我們不寫jsonpCallback時,jQuery會自動生成唯一不同的函數名)。就如同上面的dosome1,2,3,各自引用並處理。
而使用同樣的函數名時,迴圈時window['dosome']順序被賦值,最終指向最後一個處理函數(如圖中紅線),其他的都被回收了。第一個返回時執行,把內容賦值到最後一個局部變數。
這樣,第一個請求會拿不到返回內容從而fail,而最後一個請求的回調卻處理了不是自己請求的內容。