如何解決jquery.jsonp在併發下容易發生異常的bug

SBDavid發表於2018-05-11

先上原始碼: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
            })

複製程式碼

相關文章