javascript
zepto源码研究 - ajax.js($.ajaxJSONP 的分析)
簡要:jsonp是一種服務器和客戶端信息傳遞方式,一般是利用script元素賦值src來發(fā)起請求。一般凡是帶有src屬性的元素發(fā)起的請求都是可以跨域的。
那么jsonp是如何獲取服務器的數(shù)據(jù)的呢?
jsonp先將指定的一個函數(shù)名作為url后面的參數(shù)傳遞到服務器,服務器取得函數(shù)名并將要傳遞的數(shù)據(jù)形成json格式與函數(shù)名包裝起來形成腳本傳遞給客戶端執(zhí)行。
/*** jsonp請求* @param options* @param deferred* @returns {*}*/$.ajaxJSONP = function(options, deferred){//未設置type,就走 ajax 讓參數(shù)初始化.//如直接調(diào)用ajaxJSONP,type未設置if (!('type' in options)) return $.ajax(options)var _callbackName = options.jsonpCallback, //回調(diào)函數(shù)名//得到最終的回調(diào)函數(shù)名,callbackName為回調(diào)函數(shù)名稱callbackName = ($.isFunction(_callbackName) ?_callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), //沒有回調(diào),賦默認回調(diào)script = document.createElement('script'),originalCallback = window[callbackName], //回調(diào)函數(shù) responseData,//中斷請求,拋出error事件//這里不一定能中斷script的加載,但在下面阻止回調(diào)函數(shù)的執(zhí)行abort = function(errorType) {$(script).triggerHandler('error', errorType || 'abort')},xhr = { abort: abort }, abortTimeout//xhr為只讀deferredif (deferred) deferred.promise(xhr)//監(jiān)聽加載完,加載出錯事件$(script).on('load error', function(e, errorType){//清除超時設置timeout clearTimeout(abortTimeout)//刪除加載用的script。因為已加載完了,.off()清除掉綁定到dom的所有事件 $(script).off().remove()//錯誤調(diào)用errorif (e.type == 'error' || !responseData) {ajaxError(null, errorType || 'error', xhr, options, deferred)} else {//成功調(diào)用successajaxSuccess(responseData[0], xhr, options, deferred)}//回調(diào)函數(shù)window[callbackName] = originalCallbackif (responseData && $.isFunction(originalCallback))originalCallback(responseData[0])//清空閉包引用的變量值,不清空,需閉包釋放,父函數(shù)才能釋放。清空,父函數(shù)可以直接釋放originalCallback = responseData = undefined})if (ajaxBeforeSend(xhr, options) === false) {abort('abort')return xhr}//回調(diào)函數(shù)設置,給后臺執(zhí)行此全局函數(shù),數(shù)據(jù)塞入window[callbackName] = function(){responseData = arguments}//回調(diào)函數(shù)追加到請求地址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}$.ajaxJSONP(option,deffered) 這個方法在$.ajax中被調(diào)用,jsonp的請求和異步請求形式很像,但jsonp和ajax異步請求要嚴格去分開,jsonp是腳本加載形式。
但在zepto里面,jsonp和ajax請求做了形式上的融合,都是調(diào)用$.ajax方法,那么在$.ajax里面針對jsonp請求做出了哪些處理呢?
var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url);if (hasPlaceholder) dataType = 'jsonp'//不設置緩存,加時間戳 '_=' + Date.now()// 當settings.cache === null時if (settings.cache === false || ((!options || options.cache !== true) &&('script' == dataType || 'jsonp' == dataType)))//Date.now() == 1471504727756settings.url = appendQuery(settings.url, '_=' + Date.now())//如果是jsonp,調(diào)用$.ajaxJSONP,不走XHR,走scriptif ('jsonp' == dataType) {if (!hasPlaceholder) //判斷url是否有類似jsonp的參數(shù)settings.url = appendQuery(settings.url,settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')return $.ajaxJSONP(settings, deferred)}1:首先判斷settings.dataType ,如果是jsonp格式則在url后面添加settings.jsonp = ?,默認添加callback=?。然后再調(diào)用$.ajaxJSONP方法。但這里為什么不直接調(diào)用$.ajaxJSONP而多出一步呢?這里會校驗url,如果url后面有callback=?的形式,則dataType強制為jsonp。其實這里將hasPlaceholder作為$.ajaxJSONP的第三個參數(shù),然后將settings.url的參數(shù)的處理放在$.ajaxJSONP內(nèi)部進行,也是可以的。但作者為了能使$.ajaxJSONP重用并符合語義化要求,也就默認認定傳入其中的settings參數(shù)帶有callback=?的形式。
2:對于settings.url做appendQuery處理,其實就是保證settings.url后面一定得跟一個形式為callback=?的參數(shù),如果之前url后面有,則不做處理。appendQuery是個工具,如果我們有在url后面加入?yún)?shù)的功能的時候,用它就可以了。
3:調(diào)用$.ajaxJSONP ,
流程總結(jié)如下:
1:獲取url參數(shù)中的回調(diào)函數(shù)名callbackName,若沒有則默認一個。
2:將callbackName函數(shù)對象保存起來。callbackName將在下面引用一個新的函數(shù)。
3:創(chuàng)建一個新腳本元素命名為script。
3:$(script).on("load error",function(){.....})
4:判斷ajaxBeforeSend,是否中斷請求
5:callbackName引用 function(){responseData = arguments},其作用是獲取腳本里面的參數(shù)內(nèi)容,然后以類似ajax的形式返回數(shù)據(jù)。
6:將options.url最后的callback=?換成callback=callbackName,并賦值給script.src。
7:設置超時處理
$(script).on("load error",function(){.....})中大致內(nèi)容如下:
1:清除超時設置。2:off()清除掉script綁定的所有事件后清除掉remove()。
3:若e.type == 'error' 或者 responseData為空,觸發(fā)ajaxError,否則觸發(fā)ajaxSuccess。
4:將原來的callbackName傳入responseData運行。
5:很重要的一步,釋放內(nèi)存。
?
以下是關(guān)于jsonp的服務器與客戶端任務流程圖:
?
轉(zhuǎn)載于:https://www.cnblogs.com/zhutao/p/5841893.html
總結(jié)
以上是生活随笔為你收集整理的zepto源码研究 - ajax.js($.ajaxJSONP 的分析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实训三(cocos2dx 3.x 打包a
- 下一篇: spring之:XmlWebApplic