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


          問題描述

            在jquery或zepto下,循環(huán)調(diào)用同一個(gè)jsonp

            

          復(fù)制代碼
           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);
          }
          });
          }
          復(fù)制代碼

            結(jié)果

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

           

          問題解釋

            觀察jsonp的源碼

            

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

            問題出在多線程處理。 當(dāng)?shù)谝粋€(gè)jsonp剛執(zhí)行完callback,賦了值時(shí),此時(shí),script的load事件還未觸發(fā)。第二個(gè)JSONP開始初始化。然后第一個(gè)script的load開始執(zhí)行,但它的數(shù)據(jù)已被清掉了

              第一個(gè)jsonp剛執(zhí)行完callback,響應(yīng)數(shù)據(jù)賦給了 responseData 

            

          復(fù)制代碼
          //回調(diào)函數(shù)設(shè)置,給后臺(tái)執(zhí)行         window[callbackName] = function(){
          /* console.info('callbackName arguments ');
          console.info(arguments[0]);
          */ responseData = arguments
          /*console.info('responseData ');
          console.info(responseData);
          */ }
          復(fù)制代碼

           

          第二個(gè)JSONP開始初始化。沒錯(cuò)  responseData又被賦為undefine?。?!

            

          第一個(gè)script的load開始執(zhí)行,responseData這時(shí)判斷絕對(duì)為undefined,為毛?因?yàn)檫@是閉包,引用最后一個(gè)responseData的值。只能進(jìn)入error了。

           

          問題修復(fù)

            策略: 

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

            2,規(guī)避jsonp的響應(yīng)。改成這樣一種寫法。原理是,只用jsonp發(fā)請(qǐng)求,然后后臺(tái)執(zhí)行window.callback。

          復(fù)制代碼
          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' }); }
          復(fù)制代碼

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

          復(fù)制代碼
          //回調(diào)函數(shù)設(shè)置,給后臺(tái)執(zhí)行         window[callbackName] = function(){
          /* console.info('callbackName arguments ');
          console.info(arguments[0]);
          */ responseData = arguments
          /*console.info('responseData ');
          console.info(responseData);
          */ }
          復(fù)制代碼
          posted on 2016-04-14 10:52 孤飛燕 閱讀(239) 評(píng)論(0)  編輯  收藏 所屬分類: JSONP

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 丽江市| 巴马| 民权县| 梁河县| 姚安县| 康定县| 平湖市| 南郑县| 莲花县| 巴塘县| 房山区| 抚顺市| 樟树市| 丰都县| 宜兰市| 伊吾县| 启东市| 拉萨市| 谢通门县| 灵寿县| 库尔勒市| 噶尔县| 龙山县| 六安市| 勃利县| 呼图壁县| 巍山| 泸定县| 宣化县| 中山市| 辽宁省| 西充县| 泌阳县| 新河县| 通城县| 新竹市| 睢宁县| 大竹县| 滦平县| 罗源县| 当雄县|