简要:jsonp是一种服务器和客户端信息传递方式,一般是利用script元素赋值src来发起请求。一般凡是带有src属性的元素发起的请求都是可以跨域的。

那么jsonp是如何获取服务器的数据的呢?

jsonp先将指定的一个函数名作为url后面的参数传递到服务器,服务器取得函数名并将要传递的数据形成json格式与函数名包装起来形成脚本传递给客户端执行。

/**
* 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为回调函数名称
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。因为已加载完了,.off()清除掉绑定到dom的所有事件
$(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(){
responseData = arguments
} //回调函数追加到请求地址
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中被调用,jsonp的请求和异步请求形式很像,但jsonp和ajax异步请求要严格去分开,jsonp是脚本加载形式。

但在zepto里面,jsonp和ajax请求做了形式上的融合,都是调用$.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() == 1471504727756
settings.url = appendQuery(settings.url, '_=' + Date.now()) //如果是jsonp,调用$.ajaxJSONP,不走XHR,走script
if ('jsonp' == dataType) {
if (!hasPlaceholder) //判断url是否有类似jsonp的参数
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=?。然后再调用$.ajaxJSONP方法。但这里为什么不直接调用$.ajaxJSONP而多出一步呢?这里会校验url,如果url后面有callback=?的形式,则dataType强制为jsonp。其实这里将hasPlaceholder作为$.ajaxJSONP的第三个参数,然后将settings.url的参数的处理放在$.ajaxJSONP内部进行,也是可以的。但作者为了能使$.ajaxJSONP重用并符合语义化要求,也就默认认定传入其中的settings参数带有callback=?的形式。

2:对于settings.url做appendQuery处理,其实就是保证settings.url后面一定得跟一个形式为callback=?的参数,如果之前url后面有,则不做处理。appendQuery是个工具,如果我们有在url后面加入参数的功能的时候,用它就可以了。

3:调用$.ajaxJSONP ,

流程总结如下:

1:获取url参数中的回调函数名callbackName,若没有则默认一个。

2:将callbackName函数对象保存起来。callbackName将在下面引用一个新的函数。

3:创建一个新脚本元素命名为script。

3:$(script).on("load error",function(){.....})

4:判断ajaxBeforeSend,是否中断请求

5:callbackName引用 function(){responseData = arguments},其作用是获取脚本里面的参数内容,然后以类似ajax的形式返回数据。

6:将options.url最后的callback=?换成callback=callbackName,并赋值给script.src。

7:设置超时处理

$(script).on("load error",function(){.....})中大致内容如下:

1:清除超时设置。2:off()清除掉script绑定的所有事件后清除掉remove()。

3:若e.type == 'error' 或者 responseData为空,触发ajaxError,否则触发ajaxSuccess。

4:将原来的callbackName传入responseData运行。

5:很重要的一步,释放内存。

以下是关于jsonp的服务器与客户端任务流程图:

zepto源码研究 - ajax.js($.ajaxJSONP 的分析)的更多相关文章

  1. zepto源码研究 - fx_methods.js

    简要:依赖fx.js,主要是针对show,hide,fadeIn,fadeOut的封装. 源码如下: // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zept ...

  2. zepto源码研究 - fx.js

    简要:zepto 提供了一个基础方法animate来方便我们运用css动画.主要针对transform,animate以及普通属性(例如left,right,height,width等等)的trans ...

  3. zepto源码研究 - ajax.js($.ajax具体流程分析)

    简要:$.ajax是zepto发送请求的核心方法,$.get,$.post,$.jsonp都是封装了$.ajax方法.$.ajax将jsonp与异步请求的代码格式统一起来,内部主要是先处理url,数据 ...

  4. zepto源码研究 - ajax.js(请求过程中的各个事件分析)

    简要:ajax请求具有能够触发各类事件的功能,包括:触发全局事件,请求发送前事件,请求开始事件,请求结束事件等等,贯穿整个ajax请求过程,这是非常有用的,我们可以利用这些事件来做一些非常有意思的事情 ...

  5. zepto源码研究 - callback.js

    简要:$.Callbacks是一个生成回调管家Callback的工厂,Callback提供一系列方法来管理一个回调列表($.Callbacks的一个私有变量list),包括添加回调函数, 删除回调函数 ...

  6. 读Zepto源码之Ajax模块

    Ajax 模块也是经常会用到的模块,Ajax 模块中包含了 jsonp 的现实,和 XMLHttpRequest 的封装. 读 Zepto 源码系列文章已经放到了github上,欢迎star: rea ...

  7. zepto源码研究 - zepto.js - 1

    简要:网上已经有很多人已经将zepto的源码研究得很细致了,但我还是想写下zepto源码系列,将别人的东西和自己的想法写下来以加深印象也是自娱自乐,文章中可能有许多错误,望有人不吝指出,烦请赐教. 首 ...

  8. zepto源码研究 - deferred.js(jquery-deferred.js)

    简要:zepto的deferred.js 并不遵守promise/A+ 规范,而在jquery v3.0.0中的defer在一定程度上实现了promise/A+ ,因此本文主要研究jquery v3. ...

  9. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 二八║ Nuxt 基础:面向源码研究Nuxt.js

    前言 哈喽大家周五好,又是一个开开心心的周五了,接下来就是三天小团圆啦,这里先祝大家节日快乐咯,希望都没有加班哈哈,今天公司发了月饼,嗯~时间来不及了,上周应该搞个活动抽中几个粉丝发月饼的,下次吧,这 ...

随机推荐

  1. MFC一个令人纠心的错误

    IDE生成的代码,运行几次之后开始出现以下这个错误 Error: must call SetScrollSizes() or SetScaleToFitSize() before painting s ...

  2. Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建

    Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建 由于公司里的Solr调试都是用远程jpda进行的,但是家里只有一台电脑所以不能jpda进行调试,这是因为jpda的端口冲突.所以 ...

  3. [转]C# FileSystemWatcher监控指定文件或目录的文件的创建、删除、改动、重命名等活动

    觉得这个很常用..比如一些软件.   http://www.rabbit8.cn/DoNet/407.html   FileSystemWatcher控件主要功能: 监控指定文件或目录的文件的创建.删 ...

  4. IDE 常用快捷键记录

    一:Eclipse (1)删除当前行:Ctrl+D (2)最大化当前编辑窗口:Ctrl+m (3)关闭当前编辑器窗口:Ctrl+F4/Ctrl+w (4)导入依赖包:Ctrl+Shift+o 二:Ne ...

  5. Cracking the coding interview--Q2.4

    Write code to partition a linked list around a value x, such that all nodes less than xcome before a ...

  6. DEDECMS调用最新评论

    {dede:feedback row='5' titlelen='24' infolen='80'} <div class="yhplk"><div>[fi ...

  7. (转载)php反射类 ReflectionClass

    (转载)http://hi.baidu.com/daihui98/item/a67dfb8213055dd75f0ec165   php反射类 ReflectionClass 什么是php反射类,可以 ...

  8. 下载gtest

    gtest的官网地址:https://github.com/google/googletest 方式一:下载打包好的版本 在github的页面上可以直接下载打包好的gtest,下载入口如下图所示: 方 ...

  9. in, out, ref

    C#中的函数传递方式可以为in.out.ref(引用) in方式的是默认的传递方式,即向函数内部传送值,不作讲解 很多语言都有类似的操作从函数向调用者返回值,这样我们可以通过函数的调用返回多个值,因为 ...

  10. UVALive 6198 A Terribly Grimm Problem

    题目大意是 给出L,H      10^10范围 为[L, H]这个连续的整数区间寻找一个序列. 序列的长度要跟[L, H]一样 然后序列中的数都是素数,并且互不相同 并且序列中第i个数 要求是L + ...