先上原始碼:git
知道現在使用jsonp的公司越來越少了,似乎有比jsonp更好的跨域方案。但是我發現騰訊視屏、愛奇藝視訊、優酷土豆等大型網際網路公司還在使用它時,我決定寫一篇文章徹底解決jsonp在併發條件下報錯的問題。畢竟jsonp有最好的相容性。
1. 為什麼會報錯
你是不是見過以下錯誤,通常在併發情況下容易出現這個錯誤,而且是否出錯有隨機性。
Uncaught ReferenceError: XXX is not defined
複製程式碼
1.1 相同的jsonpCallback
造成以上錯誤的原因是使用了相同的jsonpCallback,由於jquery將jsonpCallback賦值到window上,並且請求完成後會刪除回撥方法,所以當兩個jsonp請求使用相同的jsonpCallback時就會造成衝突。
1.2 每個請求都使用不同的jsonpCallback就沒有問題嗎?
如果每個請求都使用不同的jsonpCallback是可以解決以上報錯問題,但是這會引發服務端效能問題。因為服務端可以通過CDN對相同的請求進行快取,如果每次jsonpCallback都不同,服務端快取就會失效,流向直接衝擊源站。所以對用相同引數的jsonp請求jsonpCallback必須是相同的。如果不同引數或url的jsonp請求使用了相同的jsonpCallback,我們可以在jsonpCallback後面加隨機數。
1.3 那完全相同的jsonp請求在併發時如何處理jsonpCallback衝突的BUG?
如果出現這種情況,我們在傳送請求前判斷當前是否有相同的jsonp請求正在傳送,如果發生衝突則取消本次請求,等到上一次請求完成後再重新請求。也就是說把併發的請求轉換為穿行執行。
有些人說可以使用async直接把並行轉為穿行,不好意思這個引數在jsonp中是無效的。
1.4 一個隱祕的BUG
上面提到的解決方案有一個隱祕的BUG。如果不使用jsonp方法返回的延遲物件的話,以上方法沒有問題。但是如果使用了延遲物件,你會發現返回的defferd物件可能永遠無法觸發resolve或者reject。這是應為在發現衝突後jsonp請求被取消,所以請求根本沒有發出,jsonp根本不返回defferd物件。這個問題也不難解決,我們可以定義自己的defferd物件,當請求完成後手動觸發resolve或者reject。這一切都已經在最終的解決方案中實現了。
2. 如何使用呢?
2.0 安裝
npm i jsonp-bugfree
2.1 依賴
- jquery 這個不用說,依賴$.ajax()方法
- md5 其實這個不是必須的,使用它的目的是為了判斷請求的url和引數是否和其他請求相同。因為url+引數可能是一個非常長的字串,使用md5可以控制字元長度。如果你不想使用md5也可以使用其他方法代替。
2.2 引入模組
支援amd、commonjs、script標籤直接引用。
2.3 demo
var myjsonp = new jsonpBugfree();
myjsonp.JSONP({
url: 'http://url',
data: {
test: 1
},
cache: true,
dataType: 'jsonp',
jsonp: 'cb',
jsonpCallback: 'jsonpCallback',
success: function () {
}
})
.then(function () {
// todo
})
.catch(function () {
// todo
})
複製程式碼