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

Jer*_*oen 7 javascript ajax jquery jsonp

当我执行多个jsonp请求时,我在jQuery中遇到问题,所有这些请求都具有相同的jsonpCallback函数.似乎只针对其中一个回调函数被触发.JSONP请求是否以某种方式相互覆盖?

下面是对github执行2个jsonp请求的示例,即使两个firebug都显示它们都返回,但getName只调用其中一个回调函数:

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]);
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*ini 20

由于jsonp的工作方式,您的请求只被触发一次.

Jsonp意味着从外部域向页面添加脚本标记,以绕过现代浏览器中构建的跨站点脚本保护(现在是2011年4月的IE6和7).为了让该脚本与页面上的其余脚本进行交互,加载的脚本需要调用页面上的函数.该函数必须存在于全局命名空间中,这意味着该名称只能有一个函数.换句话说,没有JQuery,单个jsonp请求将如下所示:

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

其中something.js看起来像这样:

loadJson({name:'Joe'})
Run Code Online (Sandbox Code Playgroud)

在这种情况下,something.js有一个硬编码的回调来加载它携带的JSON,页面有一个硬编码的loadJson函数,等待像这样的脚本加载和调用它.

现在假设您希望能够从多个源加载json并告诉每个源何时完成,或者甚至多次从同一源加载JSON,并且能够告知每个调用何时完成 - 即使一个调用延迟了很长时间之后的电话.这种硬编码方法不再适用,原因有两个:

  1. 每次加载something.js都会调用相同的loadJson()回调 - 你无法知道哪个请求与哪个回复有关.

  2. 缓存 - 一旦你加载something.js一次,浏览器就不会再向服务器询问它 - 它只是将它从缓存中恢复,破坏了你的计划.

您可以通过告诉服务器每次都以不同方式包装JSON来解决这两个问题,并且简单的方法是在查询字符串参数中传递该信息?callback=loadJson12345.好像你的页面看起来像这样:

<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>
Run Code Online (Sandbox Code Playgroud)

使用JQuery,这些都是抽象的,看起来像是对.ajax的正常调用,这意味着你期望触发成功函数.为了确保为每个jsonp加载触发正确的成功函数,JQuery在全局命名空间中创建一个长的随机回调函数名称,如JQuery1233432432432432,将其作为查询字符串中的回调参数传递,然后等待加载脚本.如果一切正常,加载的脚本将调用JQuery请求的回调函数,而后者又从$ .ajax调用中触发成功处理程序.

请注意,"正常工作"要求服务器端读取?callback查询字符串参数并将其包含在响应中,例如?callback=joe- > joe({....如果它是静态文件或服务器不以这种方式播放,您可能需要将该文件视为可缓存 - 请参阅下文.

高速缓存

如果你想让你的json缓存,你可以通过设置cache:true并将jsonpCallback属性设置为硬编码到可缓存的json文件中的字符串,让JQuery更接近我的第一个例子.例如这个静态json:

loadJoe({name:'Joe'})
Run Code Online (Sandbox Code Playgroud)

可以像这样在JQuery中加载和缓存:

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