【问题标题】:Nested jQuery AJAX requests complete in strange order嵌套的 jQuery AJAX 请求以奇怪的顺序完成
【发布时间】:2015-04-24 01:54:56
【问题描述】:

这是对我在my previous question 中遇到的问题的重述,我认为该问题受到 X,Y 问题的影响。我希望这个问题更接近我遇到的问题的核心。代码见 Github 上的scchange.js

问题

我有一组延迟的 jQuery 对象,我在上面调用 $.when。这些是向修改数据的服务器发送 POST 请求的函数。 $.when 调用包含在 $.get 回调中。这会请求我将要修改的数据字段,以满足授权要求。代码如下:

$.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
  console.log('get callback reached');
  $.when.apply($j, phoneAjaxCalls).done(function () {
    console.log('phoneAjaxCalls promises resolved');
    returnToStudentContacts();
  });
});

我正在使用phoneAjaxCalls.push(newPhone(tlcPhone,studentsdcid))将ajax调用推送到数组,newPhone返回一个ajax延迟对象:

function newPhone(tlcPhone, studentsdcid) {
    //Create new phone
    return function() {
        return $j.ajax({
            type: 'POST',
            url: '/admin/changesrecorded.white.html',
            data: tlcPhone
        });    
    };
}

运行此代码时,我在控制台中看到打印了“达到回调”之前“phoneAjaxCalls promises resolved”,这表明请求是按照它们的顺序发送的显示在代码中。但是,Chrome 的 DevTools Network 选项卡似乎表明 phoneAjaxCalls 网络请求在 phoneTlcForm.html 文档加载之前完成。

前6个请求都是phoneAjaxCalls请求,最后一个请求是来自$.getphoneTlcForm.html,但应该是第一个!

后端接收这些请求的顺序似乎与“网络”选项卡显示的顺序相同,因为我在对这些 phoneAjaxCalls 请求的响应中遇到授权错误。

需要发生的是,对phoneTlcForm.html 的请求应该在任何phoneAjaxCalls 请求发出之前完成。

背景

我的项目是一个插件,所以我不能修改后端逻辑来简化这个过程。我正在与之交互的系统在创建或更新数据时有一定的授权要求。后端系统必须“看到”我要修改的数据字段在发送修改数据的请求之前 呈现在 HTML 页面中。这就是为什么我需要在其他请求之前加载 phoneTlcForm.html 页面。

【问题讨论】:

    标签: javascript jquery ajax promise


    【解决方案1】:

    这里发生的情况是,当您构建phoneAjaxCalls 数组时,您为每个单独的项目调用$j.ajax。一旦您拨打电话,每个请求都会发出。
    我猜当你调用$j.when.apply($j, phoneAjaxCalls) 时,那里的大部分promise 都已经解决了,并且立即调用了done 回调。

    让我尝试用一​​些 cmets 来说明:

    // previous ajax requests already fired!
    $j.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
      console.log('get callback reached');
      // inspect the state of phoneAjaxCalls here
      // they might be resolved already.
    
      // you want to exec those ajax calls here, not before!
      $j.when.apply($j, phoneAjaxCalls).done(function () {
        console.log('phoneAjaxCalls promises resolved');
        returnToStudentContacts();
      });
    });
    

    所以从这里你有不同的方法来解决它。我想你已经在question you linked得到了很好的回应。

    在您返回 $j.ajax 的每个地方,您都可以返回一个包装它的函数,以避免执行。我们以updateEmail function为例:

    return function(){
        return $j.ajax({
                url: '/ws/schema/table/' + config.contactsEmailTable + '/' + emailRecordId,
                data: JSON.stringify(emailUpdateData),
                dataType: 'json',
                contentType: "application/json; charset=utf-8",
                type: 'PUT'
            });
     };
    

    包装完所有这些后,您可以这样称呼它们:

    $.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
      var phoneAjaxCallsPromises = $.map(phoneAjaxCalls, function(c){
        return c();
      });
      $.when.apply($j, phoneAjaxCalls).done(function () {
        console.log('phoneAjaxCalls promises resolved');
        returnToStudentContacts();
      });
    }); 
    

    这个解决方案感觉像是一个 hack,但了解问题可能使您能够实施正确的修复。

    【讨论】:

    • 为什么将promise对象推入phoneAjaxCalls数组会调用promise?我认为您可以传递承诺/延迟,并且在您使用 then() 或 done() 之前它们不会执行。
    • 这就是 $.ajax、$.get 等的行为。一旦你调用,请求就会被触发,并且会返回一个 Promise 来跟踪它的状态。您可以传递承诺,但 done() 调用与触发实际执行无关。
    • 我知道这里不受欢迎,但非常感谢!你帮助修复了一个引起很多头痛的错误,我学到了一些东西:D
    • 谢谢!超级高兴能帮上忙!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 2017-07-03
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    相关资源
    最近更新 更多