jQuery中并行JSONP请求不触发多个"回调事件"?多个、回调、事件、jQuery

2023-09-10 16:28:05 作者:45°仰望漫天烟火

我遇到jQuery的一个问题,当我做多JSONP请求,都具有相同的jsonpCallback功能。似乎只有对这些回调函数之一被触发。难道JSONP请求以某种方式互相覆盖?

下面做2 JSONP请求github上,尽管这两个萤火显示,他们两人回归,回调函数的getName 的例子只要求其中之一

 函数的getName(响应){
    警报(response.data.name);
}

功能用户信息(用户名){
    $阿贾克斯({
        网址:https://api.github.com/users/+用户名,
        jsonpCallback:的getName,
        数据类型:JSONP
    });
}

用户= [托沃兹,推特,jQuery的]
对于(VAR I = 0; I< users.length;我++){
  用户信息(用户[I]);
}
 

解决方案

您的请求,因为如何JSONP作品触发一次。

JSONP意味着添加脚本标记的网页从外部域来解决建设成为现代浏览器跨站点脚本保护(现在的IE6和7 2011年4月)。为了具有该脚本与页面上的脚本的其余部分交互,脚本被加载在需要调用页上的功能。该函数具有全局命名空间存在,这意味着只能有一个功能叫那个名字。换句话说,不JQuery的一个JSONP请求是这样的:

 <脚本>
功能loadJson(JSON){
    //读取JSON
}
< / SCRIPT>
&LT;脚本的src =// outsidedomain.com/something.js"></script>
 
前端点滴 JS核心 三 使用 Ajax 实现多表联动 优化 XML FromData对象 跨域请求

在哪里something.js是这样的:

  loadJson({名称:'乔'})
 

something.js在这种情况下,有一个硬codeD回调加载它所携带的JSON,并在页面有一个硬codeD loadJson功能等待像这样的加载并调用它的脚本。

现在假设您希望能够从多个来源加载JSON,告诉每一个完成时,甚至来自同一源中加载JSON多次,并且能够告诉在每次调用时结束 - 即使一个呼叫被延迟等等以后的调用后长时间完成。这种硬codeD的做法是不会工作了,有两个原因:

something.js的每一个负载调用相同loadJson()回调 - 你没有办法知道哪个请求与哪个答复

缓存 - 一旦你加载something.js一次,浏览器不会向服务器请求再次 - 这将只是从缓存中把它带回来的,毁了你的计划

您可以告诉服务器每次敷JSON不同的解决这两个,而简单的方法是通过在一个查询参数的信息,如?回调= loadJson12345 。就好像你的网页是这样的:

 &LT;脚本&GT;
功能loadJson1(JSON){
    //读取JSON
}
功能loadJson2(JSON){
    //读取JSON
}
&LT; / SCRIPT&GT;
&LT;脚本的src =// outsidedomain.com/something.js?callback=loadJson1"></script>
&LT;脚本的src =// outsidedomain.com/somethingelse.js?callback=loadJson2"></script>
 

使用jQuery,这是所有抽象让你看起来像到$就正常呼叫,这意味着你期待成功的功能来触发。为了确保正确的成功,函数火灾每个JSONP负荷,JQuery的创建像JQuery1233432432432432全局命名空间中一个长的随机回调函数的名称,通过该作为查询字符串回调参数,然后等待脚本加载。如果一切运行正常加载脚本调用回调函数JQuery的要求,这反过来又触发在$就调用成功处理程序。

请注意是正常工作要求服务器端读?回调查询参数,并包括在响应,如?回调=乔 - > 乔({... 如果它是一个静态文件或服务器不玩这种方式,你可能需要。将这个文件看作缓存 - 参见下文

缓存

如果你想你的JSON缓存,你可以JQuery的做一些设置缓存更接近我的第一个例子:真与jsonpCallback属性设置为一个字符串,它是很难codeD放入缓存JSON文件。例如,这静态JSON:

  loadJoe({名称:'乔'})
 

可以加载并缓存在JQuery的像这样:

  $。阿贾克斯({
    网址://outsidedomain.com/loadjoe.js,
    数据类型:JSONP,
    缓存:真正的,
    jsonpCallback:loadJoe,
    成功:函数(JSON){...}
});
 

I am experiencing an issue in jQuery when I do multiple jsonp requests, all with the same jsonpCallback function. It seems that only for the one of those the callback function is triggered. Are JSONP requests somehow overwriting each other?

Below an example of doing 2 jsonp request to github, and even though both firebug shows that both of them return, the callback function getName is only called for one of them:

function getName(response){
    alert(response.data.name);
}

function userinfo(username){
    $.ajax({
        url: "https://api.github.com/users/" + username,
        jsonpCallback: 'getName',
        dataType: "jsonp"
    });        
}

users = ["torvalds", "twitter", "jquery"]
for(var i = 0; i < users.length; i++){
  userinfo(users[i]);
}

解决方案

Your request fired only once because of how jsonp works.

Jsonp means adding a script tag to the page from an outside domain to get around Cross-Site Scripting protections built into modern browsers (and now IE6 and 7 as of April 2011). In order to have that script interact with the rest of the script on the page, the script being loaded in needs to call a function on the page. That function has to exist in the global namespace, meaning there can only be one function by that name. In other words, without JQuery a single jsonp request would look like this:

<script>
function loadJson(json) {
    // Read the json
}
</script>
<script src="//outsidedomain.com/something.js"></script>

Where something.js would look like this:

loadJson({name:'Joe'})

something.js in this case has a hard-coded callback to load the JSON it carries, and the page has a hard-coded loadJson function waiting for scripts like this one to load and call it.

Now suppose you want to be able to load json from multiple sources and tell when each finishes, or even load JSON from the same source multiple times, and be able to tell when each call finishes - even if one call is delayed so long it completes after a later call. This hard-coded approach isn't going to work anymore, for 2 reasons:

Every load of something.js calls the same loadJson() callback - you have no way of knowing which request goes with which reply.

Caching - once you load something.js once, the browser isn't going to ask the server for it again - it's going to just bring it back in from the cache, ruining your plan.

You can resolve both of these by telling the server to wrap the JSON differently each time, and the simple way is to pass that information in a querystring parameter like ?callback=loadJson12345. It's as though your page looked like this:

<script>
function loadJson1(json) {
    // Read the json
}
function loadJson2(json) {
    // Read the json
}
</script>
<script src="//outsidedomain.com/something.js?callback=loadJson1"></script>
<script src="//outsidedomain.com/somethingelse.js?callback=loadJson2"></script>

With JQuery, this is all abstracted for you to look like a normal call to $.ajax, meaning you're expecting the success function to fire. In order to ensure the right success function fires for each jsonp load, JQuery creates a long random callback function name in the global namespace like JQuery1233432432432432, passes that as the callback parameter in the querystring, then waits for the script to load. If everything works properly the script that loads calls the callback function JQuery requested, which in turn fires the success handler from the $.ajax call.

Note that "works properly" requires that the server-side reads the ?callback querystring parameter and includes that in the response, like ?callback=joe -> joe({.... If it's a static file or the server doesn't play this way, you likely need to treat the file as cacheable - see below.

Caching

If you wanted your json to cache, you can get JQuery to do something closer to my first example by setting cache: true and setting the jsonpCallback property to a string that is hardcoded into the cacheable json file. For example this static json:

loadJoe({name:'Joe'})

Could be loaded and cached in JQuery like so:

$.ajax({
    url: '//outsidedomain.com/loadjoe.js',
    dataType: 'jsonp',
    cache: true,
    jsonpCallback: 'loadJoe',
    success: function(json) { ... }
});