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,而最后一個請求的回調卻處理了不是自己請求的內容。