以与Ajax请求相同的顺序处理Ajax响应

时间:2015-03-17 19:52:31

标签: javascript jquery ajax

我想保护我的代码以确保用户操作按特定顺序触发的几个Ajax请求将以相同的顺序处理其响应。

我想保持Ajax的异步机制。只需保护我的代码,以避免可能导致我的网页混乱的无序响应。

要完全清楚。我们来举个例子:

$('#button1').click(function(){
  $.ajax({url: 'dosomething1.html'})
    .done( function(){ console.log('something 1 success'); } )
    .fail( function(){ console.log('something 1 failure'); } );
});

$('#button2').click(function(){
  $.ajax({url: 'dosomething2.html'})
    .done( function(){ console.log('something 2 success'); } )
    .fail( function(){ console.log('something 2 failure'); } );
});

$('#button3').click(function(){
  $.ajax({url: 'dosomething3.html'})
    .done( function(){ console.log('something 3 success'); } )
    .fail( function(){ console.log('something 3 failure'); } );
});

如果用户点击“#button1”然后点击“#button2”然后点击“button3”,我想在控制台中看到:

>something 1 success
>something 2 success
>something 3 success

可能会发生响应未按服务器发送的顺序收到。所以我想为这种情况做好准备。

注意:我事先无法知道用户触发的事件序列。所以我需要找到一种方法来“动态”链接响应处理程序。

实现这一目标的最佳解决方案是什么?

我是Ajax狡猾的新手,我今天读了大量的东西而没有找到解决方案(我想这不知何故延迟和承诺对象可以做到这一点)。 请帮助我摆脱这种可怕的头痛。 :)


编辑以通过Kevin B评论解决方案。

我努力了解我的大脑,完全理解Kevin B的例子(确实有效),直到我读了一本关于Deferreds的书,解释说“then”函数实际上是在创建一个新的Deferred并返回它的诺言。

这是与前一个“链接”的新承诺。它根据先前的承诺评估结果(已解决或拒绝)调用其成功的失败回调。

在我们的情况下,这意味着当评估前一个承诺时,还会评估“then”承诺,并将先前承诺的结果(已解决或拒绝)作为输入,以决定调用哪个回调。 在凯文B的代码中,在两种情况下都会返回ajax请求承诺(已解决或拒绝)。 因此,仅在调用“then”承诺时调用promise的.fail和.done回调,并且返回的promise(ajax请求一个)被“解析”(.done函数)或被拒绝(.fail函数)。 / p>

进一步: 我的理解是,承诺是对未来可能发生的事件的一种倾听。

在经典情况下,当事件发生时,延迟被更改为“已解决”或“已拒绝”状态,并且将调用promise回调。 承诺是“倾听”被延期的状态。触发此状态更改的事件是解决或拒绝初始事件(ajax请求,超时,其他......)。

在“then”案例中,用于评估承诺的trigerring事件是:评估引用的承诺(链中的先前承诺)(解决或拒绝)。 给定评估结果,将调用成功或失败回调。

我提出这个稍微重新组织的代码,灵感来自凯文的代码,以帮助像我这样的假人更好地理解:

var currentPromise = $.Deferred().resolve().promise();

$('#button1').click(function(){

    var button1Promise = $.ajax({url: 'dosomething1.html'})

    var thenPromise = currentPromise.then(
        function () { return button1Promise;}, 
        function () { return button1Promise;}); // to also handle fail conditions gracefully

    currentPromise = thenPromise;

    // "thenPromise" callback functions are returning the promise linked to 
    // the ajax request. So this promise is "replacing" the "thenPromise". 
    // Hence "done" and "fail" functions are finally defined for the ajax request promise.
    thenPromise.done( function(){ console.log('something 1 success'); } );
    thenPromise.fail( function(){ console.log('something 1 failure'); } );
});

希望它能帮助那些不完全理解jquery概念的人完全理解用“then”函数链接的promises。

如果我误解了某些内容,请不要犹豫。

4 个答案:

答案 0 :(得分:3)

如果您预先创建了一个承诺,您可以继续关闭它以获得所需的效果。

// ajax mock
function sendRequest(v, delay) {
    var def = $.Deferred();
    setTimeout(function () {
        def.resolve(v);
    }, delay);
    return def.promise();
}

var ajaxPromise = $.Deferred().resolve().promise();
var delay = 600; // will decrement this with each use to simulate later requests finishing sooner

// think of this as a click event handler
function doAction (btnName) {
    delay -= 100;
    var promise = sendRequest(btnName, delay);
    ajaxPromise = ajaxPromise.then(function () {
        return promise;
    }).done(function () {
        console.log(btnName);
    });
}

doAction("1");
doAction("2");
doAction("3");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

由于我将它们延迟了500毫秒,400毫秒和300毫秒,所以它们都没有记录到500毫秒之后。

以下是使用相同技术的代码:

var ajaxPromise = $.Deferred().resolve().promise();
$('#button1').click(function(){
  var promise = $.ajax({url: 'dosomething1.html'})

  ajaxPromise = ajaxPromise.then(function () {
    return promise;
  }, function () {
    return promise; // to also handle fail conditions gracefully
  }).done( function(){ console.log('something 1 success'); } )
    .fail( function(){ console.log('something 1 failure'); } );
});

// repeat for other two buttons

重要的是所有的ajax请求都会立即发送,但完成和失败的处理程序直到轮到它们才会被执行。

答案 1 :(得分:0)

  

我事先无法知道用户触发的事件序列。   因此,我需要找到一种方法来链接响应处理程序&#34;即时#34;。   

您需要管道ajax请求以使相应的响应具有相同的顺序,一种方法是使用此插件https://code.google.com/p/jquery-ajaxq/

答案 2 :(得分:0)

正如你所说:

  

我事先无法知道用户触发的事件序列。因此,我需要找到一种方法来链接响应处理程序&#34;即时#34;。

正确的方法是使用延迟对象/承诺,而不是将async参数设置为false,这可能会导致许多不必要的问题。

阅读有关如何操作的规范性介绍here

修改

使用$ {w}()同步并行任务的示例,取自here

var promiseOne, promiseTwo, handleSuccess, handleFailure;

// Promises
promiseOne = $.ajax({ url: '../test.html' });
promiseTwo = $.ajax({ url: '../test.html' });


// Success callbacks
// .done() will only run if the promise is successfully resolved
promiseOne.done(function () {
   console.log('PromiseOne Done');
});

promiseTwo.done(function () {
    console.log('PromiseTwo Done');
});

// $.when() creates a new promise which will be:
// resolved if both promises inside are resolved
// rejected if one of the promises fails
$.when(
   promiseOne,
   promiseTwo
)
.done(function () {
   console.log('promiseOne and promiseTwo are done');
})
.fail(function () {
   console.log('One of our promises failed');
});

答案 3 :(得分:-2)

这里最简单的方法是为$ .AJAX()使用async : false参数,以确保您的请求一个接一个地运行。 http://api.jquery.com/jquery.ajax/