【发布时间】:2015-03-17 19:52:31
【问题描述】:
我想保护我的代码,以确保由用户按特定顺序触发的多个 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 并返回它的承诺。
这是与前一个“链接”的新承诺。它根据之前的 Promise 评估结果(已解决或已拒绝)调用其成功的失败回调。
在我们的例子中,这意味着当前一个 promise 被评估时,“then”promise 也会被评估,并将前一个 promise 的结果(解决或拒绝)作为输入来决定调用哪个回调。 在 kevin B 的代码中,ajax 请求承诺在两种情况下都会返回(已解决或被拒绝)。 因此,只有在评估“then”promise 并且返回的 promise(ajax 请求一个)被“resolved”(.done 函数)或被拒绝(.fail 函数)时,才会调用 promise 的 .fail 和 .done 回调。
更进一步: 我的理解是,promise 是对未来可能发生的事件的一种监听器。
在经典情况下,当事件发生时,deferred 将更改为“已解决”或“已拒绝”状态并调用 promise 回调。 承诺是“监听”要更改的 deferred 的状态。触发此状态更改的事件是初始事件(ajax 请求、超时、其他...)的解决或拒绝。
在“then”的情况下,评估 promise 的触发事件是:引用的 promise(链中的前一个 promise)被评估(解决或拒绝)。 给定评估结果,调用成功或失败回调。
我提出这个受凯文代码启发的稍微重新组织的代码,以帮助像我这样的傻瓜更好地理解:
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”函数的 Promise 链接。
如果我误解了什么,请随时发表评论。
【问题讨论】:
-
您能否在处理一个请求时禁用其他按钮?例如,按下按钮 1,禁用按钮 2,禁用按钮 3。然后,在完成或失败时,重新启用所有按钮。
-
不,因为我不想阻止用户执行操作。不仅发送了 Ajax 请求。 DOM 的一些对象立即被修改。
-
有 1 个简单的选项,即让 UI 具有 3 个响应区域并在它们到来时填充它们...因为 async 表示第一次调用可能需要 20 秒来自服务器,而第二次和第三次调用可能只需要 40 毫秒...没有像你说的那样阻塞按钮,最简单的方法是在 UI 中为 3 个响应留出空间,例如
<div class="resp-1"></div><div class="resp-2"></div><div class="resp-3"></div>,并在收到响应时将其填满... -
好的,这只是一个例子。不要专注于它。 :) 我真的需要以正确的顺序处理响应。黑客无法解决问题。
-
理想情况下,当您想尽快发送请求但仍按发送顺序获取请求时,您应该使用 $.when,但是,在这种情况下 $.when 将不起作用因为你不知道你发送了多少,因为它是由用户点击触发的。您应该能够预先创建一个承诺,然后继续将请求链接到它,但这也不理想,因为您一次只能发送 1 个请求。
标签: javascript jquery ajax