我想保护我的代码以确保用户操作按特定顺序触发的几个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。
如果我误解了某些内容,请不要犹豫。
答案 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/