【问题标题】:Parallel JSONP requests in jQuery do not trigger multiple "callback events"?jQuery 中的并行 JSONP 请求不会触发多个“回调事件”?
【发布时间】:2012-05-04 14:14:23
【问题描述】:

当我使用相同的 jsonpCallback 函数执行多个 jsonp 请求时,我在 jQuery 中遇到问题。似乎只有其中之一触发了回调函数。 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]);
}

【问题讨论】:

  • 如果它们是两个成功的响应,那么我希望该函数会被触发两次。验证响应流文本。
  • 这就是我所期望的。但事实并非如此。
  • 我 认为(查看 jquery 代码并不是最简单的)当指定 jsonpCallback 时,jquery 将始终为您创建一个该名称的函数。它保存当前的(如果已定义)并在以后恢复它。我看到的基本上是竞争条件,并发 jsonP 请求“随机”失败。来自代码(v3.2.1): window[ callbackName ] = function() { responseContainer = arguments; };你同意吗?

标签: javascript ajax jquery jsonp


【解决方案1】:

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

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

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

something.js 看起来像这样:

loadJson({name:'Joe'})

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

现在假设您希望能够从多个来源加载 json 并告知每个来源何时完成,或者甚至多次从同一来源加载 JSON,并且能够告知每个调用何时完成 - 即使一个调用被延迟,所以long 它在稍后的调用后完成。这种硬编码方法不再适用,原因有两个:

  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>

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

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

缓存

如果您希望您的 json 缓存,您可以让 JQuery 做一些更接近我的第一个示例的操作,方法是设置 cache: true 并将 jsonpCallback 属性设置为硬编码到可缓存 json 文件中的字符串。例如这个静态 json:

loadJoe({name:'Joe'})

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

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

【讨论】:

  • +1 很好的解释,这对我帮助很大(差不多一年后!)
【解决方案2】:

改用成功回调..

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

【讨论】:

  • 如果这样做会很好:一个包装好的“托管随机函数”....(或者我是 jQuery 过时的?;-)
  • 它工作得很好jsfiddle.net/gaby/4BPvb jQuery 自动插入一个回调名称并使用它来评估响应..
  • 啊,我确实落后了。但是,为什么不显式名称方法起作用?
  • @pst,jsonpCallback 参数并不是处理结果的实际函数。它只是作为回调方法的名称(用于缓存和/或接收 API要求)。它由 jQuery 内部处理,如果您 look at the source 他们会出于自己的目的覆盖您的函数,并且一旦所有 ajax 请求完成,他们就会恢复它并调用它...(这就是它只运行的原因一次)
  • 它确实有效,应该是一个更受欢迎的答案。
【解决方案3】:
$(function() {
    function userinfo(username){
      var XHR = $.ajax({
             url: "https://api.github.com/users/" + username,
             dataType: "jsonp"
         }).done(function(data) {
             console.log(data.data.name);
         });
    }

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

【讨论】:

    【解决方案4】:

    不确定,但我从调用 github API 得到的响应不包括 gravatar_id。

    这对我有用:

    function getGravatar(response){
        var link = response.data.avatar_url;
        $('#list').append('<div><img src="' + link + '"></div>');
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-17
      • 2015-03-11
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      相关资源
      最近更新 更多