假设我们有两个按钮,每个按钮都调用以下方法:
var NUMBER_OF_IMAGE_REQUEST_RETRIES = 3;
var IMAGE_REQUEST_TIMEOUT = 3000;
processImage: function(image_data) {
var main_response = $q.defer();
var hash = getImageHash(image_data);
var requestsCounter = -1;
requestImage = function() {
$http.post(apiUrl, {params: {data: hash},timeout: IMAGE_REQUEST_TIMEOUT})
.then(function(response) {
return main_response.resolve(response.data);
}, function(error) {
if (++requestsCounter < NUMBER_OF_IMAGE_REQUEST_RETRIES) {
requestLabelsImage();
} else {
return main_response.reject();
}
});
};
requestLabelsImage();
return main_response.promise;
}
该方法将图像相关数据传递给服务器,服务器处理数据然后响应。每次用户按下不同的按钮时,都会向服务器发送不同的image_data
。
问题:
用户按下按钮1,使用image_data_1
调用该方法,然后他/她立即按下按钮2,并使用image_data_2
调用该方法。 processImage
函数由另一个方法调用,假设doSomethingWithTheResponse
仅关注最新用户的操作,但image_data_2
由服务器更快地进行,因此客户端得到{{1}在image_data_2
之前,客户端认为image_data_1
与用户的最新操作有关,而事实并非如此。 我们如何确保客户始终获得与用户最新操作相关的响应?
注意:不同的image_data_1
请求的哈希值不同。
我在想这样的事情:
image_data
但我并非100%确定这是正确的方法。
答案 0 :(得分:1)
简单地忽略之前的请求。
您可以创建请求存储库(数组或字典实现是可以的)。一旦发出另一个请求,当您将其添加到存储中时,请先调用之前的.abort()
。
如果你想要一本字典,那就有一个很好的例子here(虽然解决了不同的主题),但这里有一段与你的案例相关的修改后的代码片段:
var _pendingRequests = {};
function abortPendingRequests(key) {
if (_pendingRequests[key]) {
_pendingRequests[key].abort();
}
}
key
可以......说...你的行动类别。您可以为它命名常量,也可以只是按下按钮的名称。它甚至可以是您请求的URL;完全取决于你。
这里对整个概念有一个很好的解释:
jquery abort()发送另一个之前的ajax请求 https://stackoverflow.com/a/3313022/594992
答案 1 :(得分:1)
如果您的用户界面允许启动多个操作,而这些操作的处理是互斥的,那么您应该使用promises,并跟踪有效的承诺。
button1.addEventListener("click", function(evt) {
startRunning( task1.start() );
});
button2.addEventListener("click", function(evt) {
startRunning( task2.start() );
});
使用任务运行程序:
function startRunning( promise ) {
while(runningTasks.length>0) {
cancel( runningTasks.unshift() );
});
runningTasks.push( promise );
}
您的cancel
函数可能来自任何可以处理承诺的函数,例如Angular的service.cancelRequest
,或者您可以编写自己的代码来接受承诺并巧妙地中断其操作。
当然,如果你没有使用promises,那么你可能想要开始这样做,但如果你绝对不能,你可以使用像这样的经理对象:
button1.addEventListener("click", function(evt) { task1(); });
button2.addEventListener("click", function(evt) { task2(); });
与
var manager = [];
function cancelAll() {
while(manager.lenght>0) {
var cancelfn = manager.unshift()
cancelfn();
}
return true;
}
function task1() {
var running = cancelAll();
manager.push(function() { running = false; });
asyncDo(something1, function(result) {
if(!running) return;
// do your real thing
});
}
function task1() {
var running = cancelAll();
manager.push(function() { running = false; });
asyncDo(something2, function(result) {
if(!running) return;
// do your real thing
});
}
您可以根据需要在多个方面取消。如果您需要取消运行XHR,您可以这样做,如果您在结果处理中有多个步骤,在每个步骤开始时切断等等。
答案 2 :(得分:0)
这听起来像是承诺的理想用例。基本上,无论何时发出新请求,您都希望取消任何现有的承诺。我不熟悉AngularJS,但以下特定于ng的链接可能有用:
Angularjs how to cancel resource promise when switching routes