-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
原来你是这样的jsonp(原理与具体实现细节) #4
Comments
var script = document.createElement('script'); 这里console.log输出顺序是: 全局函数执行 ---> load事件触发,这个顺序如何保证?看zepto的源码这个顺序是对的,也是能保证的,里面的原理是什么呢?你知道吗? |
@ployer900 不好意思回复晚了,其实Zepto中也没有做什么处理,因为script元素的load事件本身表示的是其指向的资源已完成加载时才触发,所以顺序是按照你说的这种来的。 |
老哥,帮到我了,谢谢。 |
@liumt1993 很开心能对你有帮助,嘿嘿。 |
老哥,看到你的文章,你的md中有不少乱码字符?,我之前遇到过,是用vscode开着preview时遇到的,参考链接。强迫症表示不能忍 |
@bmxklYzj 哈哈,感谢。已经去掉了,舒服多了。哈哈 |
跨域之后有数据返回,但是老是进入到error里面,怎么办? |
使用jsonp跨域请求后可以获得数据,但是进入error方法,返回parseerror,检查了服务端日志,返回的是string也可以自己设置成数组,但是前端从控制台看有数据返回,但是不进入success里面而直接进入到error里面 |
前言
原文地址
仓库地址
让我们从zepto.js的源码出发,一步步揭开它的面纱。
(该篇文章重点是想说jsonp实现过程,如果你想了解跨域相关的更多的知识,可以谷歌,度娘一把)
絮叨一下jsonp的基本原理
基本思想是啥呢
客户端利用
script
标签可以跨域请求资源的性质,向网页中动态插入script
标签,来向服务端请求数据。服务端会解析请求的
url
,至少拿到一个回调函数(比如callback=myCallback
)参数,之后将数据放入其中返回给客户端。当然jsonp不同于平常的
ajax
请求,它仅仅支持get类型的方式如何使用
使用
在zepto中一个常见的jsonp请求配置就是这样了,大家都很熟悉了。但是不知道大家有没有发现.
timeout
超时了,并且没有设置jsonpCallback
字段,那么控制台几乎都会出现一处报错,如下图timeout
,此时如果请求超时了,并且设置了jsonpCallback
字段(注意这个时候是设置了),但是如果请求在超时之后完成了,你的jsonpCallback
还是会被执行。照理说这个函数应该是请求在超时时间内完成才会被执行啊!为毛这个时候超时了,还是会被执行啊!!!不急等我们一步步分析完就会知道这个答案了。
先看一下完整的代码
参数的基本处理
我们先来看看针对上面的例子我们发送请求的url最终会变成什么样子,而参数处理正是为了得到这条url
传了jsonpCallback时的url
http://www.abc.com/api/xxx?name=qianlongo&sex=boy&_=1497193375213&callback=globalCallback
没有传jsonpCallback时的url
http://www.abc.com/api/xxx?name=qianlongo&sex=boy&_=1497193562726&callback=Zepto1497193562723
相信你已经看出来这两条url有什么不同之处了。
_后面跟的时间戳不一样
callback后面跟的回调函数名字不一样
也就是说如果你指定了成功的回调函数就用你的,没指定他自己生成一个。
上参数处理代码
对于回调函数名的处理其实挺简单的,根据你是否在参数中传了
jsonpCallback
,传了是个函数就用函数的返回值,不是函数就直接用。否则的话,就生成类似
Zepto1497193562723
的函数名。继续看
好啦,看到这里我们主要要关注的是
originalCallback = window[callbackName]
abort
函数对于1为什么要把全局的
callbackName
函数先保存一份呢?这里涉及到一个问题。请求回来的时候到底是不是直接执行的你传入的jsonpCallback函数?
解决这个问题请看
zepto中把全局的
callbackName
函数给重写掉了,,导致后端返回数据时执行该函数,就干了一件事,就是把数据赋值给了responseData
这个变量。那说好的真正的
callbackName
函数呢? 如果我传了jsonpCallback
,我是会在里面做一些业务逻辑的啊,你都把我给重写了,我的逻辑怎么办?先留个疑问在这里对于关注点2
abort函数
,这个函数的功能,就是手动触发添加在创建好的script
元素身上的error
事件的回调函数。后面的超时处理timeout
以及请求出错都是利用的该函数。超时处理
代理做了简单的注释,这里除了将
script
元素插入网页还定义了一个超时处理函数,判断条件是传入的参数timeout
是否大于0,所以当你传小于0或者负数啥的进去,是不会当做超时处理的。超时后其实就是触发了script
元素的error
事件,并传了参数timeout
真正的回调逻辑处理
script
元素真正的事件处理程序代码也不多,开头有这两句话起什么作用呢?
第一句自然是针对超时处理,如果请求在指定超时时间之前完成,自然是要把他清除一下,不然指定的时间到了,超时的回调还是会执行,这是不对的。
第二句话,把创建的script元素从网页中给删除掉,绑定的事件('load error')也全部移除,干嘛要把事件都给移除呢?你想想,一个请求已经发出去了,我们还能让他半途停止吗?该是不能吧,但是我们能够阻止请求回来之后要做的事情呀!而这个回调不就是请求回来之后要做的事情么。
请求成功或失败的处理
那么再接下来,就是请求的成功或失败的处理了。失败的条件就是触发了
error
事件(不管是超时还是解析错误,又或者状态码不在HTTP 2xx),甚至如果后端没有正确给到数据responseData
也是错误。再回顾一下responseData是怎么来的
ajaxErro函数究竟做了些啥事呢?
ajaxError
可以看到他调用了我们穿进去的
error
函数,并且触发了全局的ajaxError
钩子,所以我们其实可以在document
上监听一个钩子这个时候便可以拿到请求出错的信息了
ajaxComplete
ajaxStop
同理我们可以监听
ajaxComplete
和ajaxStop
钩子处理完失败的情况那么接下来就是成功的处理了,主要调用了
ajaxSuccess
函数ajaxSuccess
原来我们平时传入的
success
函数是在这里被执行的。但是有一个疑问啊!,我们知道我们是可以不传入success
函数的,当我们指定jsonpCallback
的时,请求成功同样会走jsonpCallback
函数,但是好像ajaxSuccess
没有执行这个函数,具体在处理的呢?继续往下看
为了彻底搞清楚zepto把我们指定的回调函数重写的原因,我再次加了重写的代码在这里。可以看出,重写的目的,就是为了拿到后端返回的数据,而拿到数据之后便方便我们在其他地方灵活的处理了,当然指定的回调函数还是要重新赋值回去(这也是开头要保留一份该函数的本质原因),如果是个函数,就将数据,塞进去执行。
分析到这里我相信你已经几乎明白了jsonp实现的基本原理,文章顶部说的几个问题,我们也在这个过程中解答了。
砰砰砰!!!,亲们还记得开头的时候留了这两个问题吗?
在zepto中一个常见的jsonp请求配置就是这样了,大家都很熟悉了。但是不知道大家有没有发现.
timeout
超时了,并且没有设置jsonpCallback
字段,那么控制台几乎都会出现一处报错,如下图timeout
,此时如果请求超时了,并且设置了jsonpCallback
字段(注意这个时候是设置了),但是如果请求在超时之后完成了,你的jsonpCallback
还是会被执行。照理说这个函数应该是请求在超时时间内完成才会被执行啊!为毛这个时候超时了,还是会被执行啊!!!问题1:为什么会报错呢?
对于没有指定
jsonpCallback
此时我们给后端的回调函数名是类似
Zepto1497193562723
超时的时候同样会走
load error
的回调,当这句话执行的时候,Zepto1497193562723
被设置成了undefined,当然后端返回数据的时候去执行自然就报错了。
问题2呢? 其实同样还是上面那句话,只不过此时我们指定了
jsonpCallback
,超时的时候虽然取消了script
元素的的load error
事件,意味着在超时之后请求即便回来了,也不会走到对应的回调函数中去。但是别忘记,超时我们手动触发了script
元素的error
事件原本被重写的callback函数也会被重新赋值回去,此刻,即便
script
元素的load error
回调不会被执行,但我们指定的jsonpCallback
还是会被执行的。这也就解了问题2.用koa做服务端,zepto发jsonp请求
如果你对源码感兴趣可以点击这里查看koa-todo-list
找到根目录的
testJsonp.js
文件即是服务端主要代码前端代码
html
js
服务端主要代码
运行截图
结尾
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
如果对你有一点点帮助,点击这里,加一个小星星好不好呀
The text was updated successfully, but these errors were encountered: