孤燈野火
          暢想的天空
          posts - 2,comments - 4,trackbacks - 0


          問題描述

            在jquery或zepto下,循環調用同一個jsonp

            

          復制代碼
           for(var i = 0;i<5;i++){
          $.ajax({
          url:
          'https://m.suning.com/authStatus?callback=checkLogin1&_=1430100870770',
          dataType:
          'jsonp',
          jsonpCallback:
          'checkLogin1',
          success:function(data){
          console.info(
          'success');
          },
          error:function(xhr,e){
          console.error(e);
          }
          });
          }
          復制代碼

            結果

            有些成功有些失敗了?這是為何?

           

          問題解釋

            觀察jsonp的源碼

            

          復制代碼
           /**
          * jsonp請求
          * @param options
          * @param deferred
          * @returns {*}
          */ $.ajaxJSONP = function(options, deferred){
          //未設置type,就走 ajax 讓參數初始化.
          //如直接調用ajaxJSONP,type未設置 if (!('type' in options)) return $.ajax(options)
          var _callbackName = options.jsonpCallback, //回調函數名 callbackName = ($.isFunction(_callbackName) ? _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), //沒有回調,賦默認回調 script = document.createElement('script'),
          originalCallback
          = window[callbackName], //回調函數 responseData,
          //中斷請求,拋出error事件
          //這里不一定能中斷script的加載,但在下面阻止回調函數的執行 abort = function(errorType) {
          $(script).triggerHandler(
          'error', errorType || 'abort')
          },
          xhr
          = { abort: abort }, abortTimeout
          //xhr為只讀deferred if (deferred) deferred.promise(xhr)
          //監聽加載完,加載出錯事件 $(script).on('load error', function(e, errorType){
          //清除超時設置timeout clearTimeout(abortTimeout)
          //刪除加載用的script。因為已加載完了 $(script).off().remove()
          //錯誤調用error if (e.type == 'error' || !responseData) {
          ajaxError(
          null, errorType || 'error', xhr, options, deferred)
          }
          else {
          //成功調用success ajaxSuccess(responseData[0], xhr, options, deferred)
          }
          //回調函數 window[callbackName] = originalCallback
          if (responseData && $.isFunction(originalCallback))
          originalCallback(responseData[
          0])
          //清空閉包引用的變量值,不清空,需閉包釋放,父函數才能釋放。清空,父函數可以直接釋放 originalCallback = responseData = undefined
          })
          if (ajaxBeforeSend(xhr, options) === false) {
          abort(
          'abort')
          return xhr
          }
          //回調函數設置,給后臺執行 window[callbackName] = function(){
          /* console.info('callbackName arguments ');
          console.info(arguments[0]);
          */ responseData = arguments
          /*console.info('responseData ');
          console.info(responseData);
          */ } //回調函數追加到請求地址 script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
          document.head.appendChild(script)
          //超時處理,通過setTimeout延時處理 if (options.timeout > 0) abortTimeout = setTimeout(function(){
          abort(
          'timeout')
          }, options.timeout)
          return xhr
          }
          復制代碼

            問題出在多線程處理。 當第一個jsonp剛執行完callback,賦了值時,此時,script的load事件還未觸發。第二個JSONP開始初始化。然后第一個script的load開始執行,但它的數據已被清掉了

              第一個jsonp剛執行完callback,響應數據賦給了 responseData 

            

          復制代碼
          //回調函數設置,給后臺執行         window[callbackName] = function(){
          /* console.info('callbackName arguments ');
          console.info(arguments[0]);
          */ responseData = arguments
          /*console.info('responseData ');
          console.info(responseData);
          */ }
          復制代碼

           

          第二個JSONP開始初始化。沒錯  responseData又被賦為undefine!!!

            

          第一個script的load開始執行,responseData這時判斷絕對為undefined,為毛?因為這是閉包,引用最后一個responseData的值。只能進入error了。

           

          問題修復

            策略: 

            1, 修改jsonp源碼。在執行callback時,將responseData,傳入監聽函數。諸如function(data){ return function( ...onload... }(responseData);這個太麻煩,而且還得注意開源協議。

            2,規避jsonp的響應。改成這樣一種寫法。原理是,只用jsonp發請求,然后后臺執行window.callback。

          復制代碼
          window.checkLogin1 = function(data){
          console.info(
          'checkLogin1 success');
          console.info(data);
          }
          for(var i = 0;i<5;i++){
          $.ajax({
          url:
          'https://m.suning.com/authStatus?callback=checkLogin1&_=1430100870770',
          dataType:
          'jsonp' }); }
          復制代碼

            切記不能加 jsonpCallback:‘checkLogin1’.原因是,jsonp會重寫window[checkLogin1].第二次請求將找不到。

          復制代碼
          //回調函數設置,給后臺執行         window[callbackName] = function(){
          /* console.info('callbackName arguments ');
          console.info(arguments[0]);
          */ responseData = arguments
          /*console.info('responseData ');
          console.info(responseData);
          */ }
          復制代碼
          posted on 2016-04-14 10:52 孤飛燕 閱讀(240) 評論(0)  編輯  收藏 所屬分類: JSONP

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 弥渡县| 同心县| 西和县| 牡丹江市| 漯河市| 贡山| 瑞丽市| 临安市| 香格里拉县| 南郑县| 抚州市| 南宁市| 内丘县| 巫山县| 宕昌县| 揭西县| 扶风县| 板桥市| 望奎县| 石台县| 西林县| 竹北市| 玉树县| 张北县| 宣化县| 碌曲县| 静宁县| 和硕县| 那曲县| 万年县| 鄂托克旗| 黄骅市| 泽普县| 儋州市| 靖宇县| 黄大仙区| 达日县| 开化县| 剑阁县| 塘沽区| 嘉祥县|