如何处理本身异步触发的异步ajax调用

时间:2021-02-06 14:29:29

I have this problem:

我有这个问题:

The user clicks on a button A, then something gets created with an ajax call. The call returns some data.

用户单击按钮A,然后使用ajax调用创建一些东西。该调用返回一些数据。

Later, the user (enteres some text into an input and) will click on button B. This will start another ajax call. Now, this one needs the returned data from the first request.

稍后,用户(将某些文本输入到输入中)将单击按钮B.这将启动另一个ajax调用。现在,这个需要第一个请求返回的数据。

This is no problem when the first call is fast enough. However, I have to assume that it could take a while, so when the user clicks on button B the first call may not be completed.

当第一个呼叫足够快时,这没有问题。但是,我必须假设它可能需要一段时间,所以当用户点击按钮B时,第一个呼叫可能无法完成。

I don't want to disable button B as long as the first lasts. The user should click on button B even if the first ajax call has not yet completed. So it seems that I need to chain/queue the calls somehow.

只要第一次持续,我就不想禁用按钮B.即使第一个ajax调用尚未完成,用户也应该单击按钮B.所以我似乎需要以某种方式对调用进行链接/排队。

How could I do this? And how could this be done with a longer sequence of calls. And is there a name for this scenario, is there already a pattern for it? Or am I just blind?

我怎么能这样做?如何通过更长的调用序列完成此操作。这个场景是否有名称,是否已经存在一种模式?还是我只是瞎了?

Rudimentary sample code:

基本示例代码:

$('button.a').click(function () {
    $.post('some/url/for/action/a', {})
        .done(function (returnedData) {

        })
});

$('button.b').click(function () {
    // now I need something from returnedData, which may not be available yet
    $.post('some/url/for/action/b', {something: returnedData.something})
        .done(function () {

        })
});

Note: the final aim is to speed up the process to improve UX.

注意:最终目标是加快改进用户体验的过程。

(Feel free to improve the title of the question. I couln't express that better.)

(随意改进问题的标题。我不能表达更好。)

4 个解决方案

#1


3  

If you're OK working with the most recent versions of the ECMAScript spec, then you may want to look at using Promises. There's a seriously great explanation of Promises on Google's documentation for the web, but they're basically objects that we can use to wait for stuff to finish happening asynchronously.

如果您可以使用最新版本的ECMAScript规范,那么您可能需要查看使用Promises。对Google的Web文档中的Promises有一个非常好的解释,但它们基本上是我们可以用来等待异步完成事情的对象。

If you wrap your first ajax call inside a Promise object, then you can come back to it later on (in your case, after the user clicks button B) and see if it's finished yet. If it has, then() you can do something in response!

如果你在Promise对象中包装你的第一个ajax调用,那么你可以稍后再回来(在你的情况下,在用户点击按钮B之后)并查看它是否已经完成。如果有,那么()你可以做出回应!

var promiseA; // this variable will hold our Promise object

function postActionA() {
  return new Promise(function(resolve, reject) {
    $.post('some/url/for/action/a', {}).done(resolve); // this is the magic
    // when the ajax call completes, it calls the 'resolve' function
  });
}

$('button.a').click(function () {
  promiseA = postActionA();
  // by assigning our promise object to a variable
  // we can inspect its state later on
  promiseA.then(function(returnedData) {
    // do stuff with returnedData here if you like
  });
});

$('button.b').click(function () {
  // assuming that promiseA was assigned earlier
  // we can wait for it to resolve, then make our next ajax call
  promiseA.then(function (returnedData) {
    $.post('some/url/for/action/b', {something: returnedData.something})
      .done(function () {
      // do something after the second ajax call completes
      });
  });
});

If you're not able to use the latest version of ECMAScript and would rather use jQuery, we can make use of jQuery's deferred objects to do something similar.

如果你不能使用最新版本的ECMAScript而宁愿使用jQuery,我们可以利用jQuery的延迟对象来做类似的事情。

var deferredA; // this variable will hold our Deferred object

$('button.a').click(function () {
  deferredA = $.post('some/url/for/action/a', {});
  // by assigning our deferred object to a variable
  // we can inspect its state later on
  deferredA.done(function(returnedData) {
    // do stuff with returnedData here if you like
  });
});

$('button.b').click(function () {
  // assuming that deferredA was assigned earlier
  // we can wait for it to resolve, then make our next ajax call
  deferredA.done(function (returnedData) {
    $.post('some/url/for/action/b', {something: returnedData.something})
      .done(function () {
      // do something after the second ajax call completes
      });
  });
});

#2


1  

My idea is based on queueing the ajax call on button click. Then the call is picked up from the queue and fired.

我的想法是基于按钮点击排队ajax调用。然后从队列中拾取呼叫并触发。

This way you can click random sequences (like A,B,A,A,B,A,B,B) and every subsequent call will wait for previous ones.

这样,您可以单击随机序列(如A,B,A,A,B,A,B,B),并且每个后续调用都将等待先前的序列。

Passing data from one call to another is done via global variable.

将数据从一个调用传递到另一个调用是通过全局变量完成的。

The code:

var queue = [];
var processing = false;
var dataFromLastCall = {}; //data from previous call

function register(callParams){
  queue.push(callParams);
  if(processing == false){
    process(queue);
  }
}

function process(){
  processing = true;
  var call = queue.shift();

  $.when(jQuery.ajax(call)).then(function(){
    if(queue.length > 0){
      process(); //get another
    }else{
      processing = false; //all done
    }
  });
}

$("button.a").click(function(e){
  e.preventDefault();
  register({
    type: 'POST',
    url: 'some/url/for/action/a',
    data: dataFromLastCall,
    success: function(newData){
      dataFromLastCall = newData;
    }
  });
});

$("button.b").click(function(e){
  e.preventDefault();
  register({
    type: 'POST',
    url: 'some/url/for/action/b',
    data: dataFromLastCall,
    success: function(newData){
      dataFromLastCall = newData;
    }
  });
});

Note, that this sample does not handle error scenarios.

请注意,此示例不处理错误方案。

#3


0  

var isFirstCallFinished = false;


$('button.a').click(function () {
$.post('some/url/for/action/a', {})
    .done(function (returnedData) {
         isFirstCalFinished = true;
    })
});

$('button.b').click(function () {
// now I need something from returnedData, which may not be available yet
setInterval(function () {
 if(isFirstCallFinished)  {
 // Cancel Interval
 // Call postMe()
 }
}, 1000);
});
function postMe() {
 $.post('some/url/for/action/b', {something: returnedData.something})
    .done(function () {

    })
  });
 }

#4


-2  

You actually want to make a synchronous call. I suggest you to use $.ajax instead of $.post since it's more customizable.

你实际上想要进行同步通话。我建议你使用$ .ajax而不是$ .post,因为它更可定制。

Your button B function would be something like this:

你的按钮B功能是这样的:

$.ajax({
  type: 'POST',
  url: 'some/url/for/action/b',
  data: data,
  success: success,
  async:false
});

The async:false option makes your request synchronous.

async:false选项使您的请求同步。

#1


3  

If you're OK working with the most recent versions of the ECMAScript spec, then you may want to look at using Promises. There's a seriously great explanation of Promises on Google's documentation for the web, but they're basically objects that we can use to wait for stuff to finish happening asynchronously.

如果您可以使用最新版本的ECMAScript规范,那么您可能需要查看使用Promises。对Google的Web文档中的Promises有一个非常好的解释,但它们基本上是我们可以用来等待异步完成事情的对象。

If you wrap your first ajax call inside a Promise object, then you can come back to it later on (in your case, after the user clicks button B) and see if it's finished yet. If it has, then() you can do something in response!

如果你在Promise对象中包装你的第一个ajax调用,那么你可以稍后再回来(在你的情况下,在用户点击按钮B之后)并查看它是否已经完成。如果有,那么()你可以做出回应!

var promiseA; // this variable will hold our Promise object

function postActionA() {
  return new Promise(function(resolve, reject) {
    $.post('some/url/for/action/a', {}).done(resolve); // this is the magic
    // when the ajax call completes, it calls the 'resolve' function
  });
}

$('button.a').click(function () {
  promiseA = postActionA();
  // by assigning our promise object to a variable
  // we can inspect its state later on
  promiseA.then(function(returnedData) {
    // do stuff with returnedData here if you like
  });
});

$('button.b').click(function () {
  // assuming that promiseA was assigned earlier
  // we can wait for it to resolve, then make our next ajax call
  promiseA.then(function (returnedData) {
    $.post('some/url/for/action/b', {something: returnedData.something})
      .done(function () {
      // do something after the second ajax call completes
      });
  });
});

If you're not able to use the latest version of ECMAScript and would rather use jQuery, we can make use of jQuery's deferred objects to do something similar.

如果你不能使用最新版本的ECMAScript而宁愿使用jQuery,我们可以利用jQuery的延迟对象来做类似的事情。

var deferredA; // this variable will hold our Deferred object

$('button.a').click(function () {
  deferredA = $.post('some/url/for/action/a', {});
  // by assigning our deferred object to a variable
  // we can inspect its state later on
  deferredA.done(function(returnedData) {
    // do stuff with returnedData here if you like
  });
});

$('button.b').click(function () {
  // assuming that deferredA was assigned earlier
  // we can wait for it to resolve, then make our next ajax call
  deferredA.done(function (returnedData) {
    $.post('some/url/for/action/b', {something: returnedData.something})
      .done(function () {
      // do something after the second ajax call completes
      });
  });
});

#2


1  

My idea is based on queueing the ajax call on button click. Then the call is picked up from the queue and fired.

我的想法是基于按钮点击排队ajax调用。然后从队列中拾取呼叫并触发。

This way you can click random sequences (like A,B,A,A,B,A,B,B) and every subsequent call will wait for previous ones.

这样,您可以单击随机序列(如A,B,A,A,B,A,B,B),并且每个后续调用都将等待先前的序列。

Passing data from one call to another is done via global variable.

将数据从一个调用传递到另一个调用是通过全局变量完成的。

The code:

var queue = [];
var processing = false;
var dataFromLastCall = {}; //data from previous call

function register(callParams){
  queue.push(callParams);
  if(processing == false){
    process(queue);
  }
}

function process(){
  processing = true;
  var call = queue.shift();

  $.when(jQuery.ajax(call)).then(function(){
    if(queue.length > 0){
      process(); //get another
    }else{
      processing = false; //all done
    }
  });
}

$("button.a").click(function(e){
  e.preventDefault();
  register({
    type: 'POST',
    url: 'some/url/for/action/a',
    data: dataFromLastCall,
    success: function(newData){
      dataFromLastCall = newData;
    }
  });
});

$("button.b").click(function(e){
  e.preventDefault();
  register({
    type: 'POST',
    url: 'some/url/for/action/b',
    data: dataFromLastCall,
    success: function(newData){
      dataFromLastCall = newData;
    }
  });
});

Note, that this sample does not handle error scenarios.

请注意,此示例不处理错误方案。

#3


0  

var isFirstCallFinished = false;


$('button.a').click(function () {
$.post('some/url/for/action/a', {})
    .done(function (returnedData) {
         isFirstCalFinished = true;
    })
});

$('button.b').click(function () {
// now I need something from returnedData, which may not be available yet
setInterval(function () {
 if(isFirstCallFinished)  {
 // Cancel Interval
 // Call postMe()
 }
}, 1000);
});
function postMe() {
 $.post('some/url/for/action/b', {something: returnedData.something})
    .done(function () {

    })
  });
 }

#4


-2  

You actually want to make a synchronous call. I suggest you to use $.ajax instead of $.post since it's more customizable.

你实际上想要进行同步通话。我建议你使用$ .ajax而不是$ .post,因为它更可定制。

Your button B function would be something like this:

你的按钮B功能是这样的:

$.ajax({
  type: 'POST',
  url: 'some/url/for/action/b',
  data: data,
  success: success,
  async:false
});

The async:false option makes your request synchronous.

async:false选项使您的请求同步。