处理迟到的响应的“正确”方法是哪种

时间:2015-05-04 18:35:33

标签: javascript angularjs asynchronous

假设我们有两个按钮,每个按钮都调用以下方法:

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%确定这是正确的方法。

3 个答案:

答案 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

     

Canceling A Promise In AngularJS