【问题标题】:How to keep track of latest request asynchronous call如何跟踪最新的请求异步调用
【发布时间】:2023-04-06 08:53:01
【问题描述】:

我有一个 AngularJS 控制器,它正在对返回承诺的服务进行异步调用。

$myService.getData(ctrl.state)
.then(function(data) {
    updateInterface(data);
});

当 promise 返回时,我正在更新界面中的数据。 但是,如果我进行了两次调用,并且第一次调用在第二次调用之后返回,那么界面将根据陈旧状态使用不正确的数据进行更新。

我想了几个办法来处理这个问题:

  • 跟踪某种类型的 Promise 标识符,当 Promise 返回时,仅在与最新的匹配时处理它。
  • 跟踪承诺,直到它返回。如果进行了另一个调用,请取消该承诺。取消可以由服务处理。

getData 方法进行 ajax 调用 ($http.get),所以我可以通过在 _httpTimeout 对象上调用 resolve() 来取消它。然而,这似乎非常特定于 Promise 中的逻辑。

是否有处理此异步问题的最佳做法? JsFiddle is here.

var testDiv = document.getElementById('test');

function loadData(query, pause) {
   var data = query;

   return new Promise((resolve, reject) => {
    setTimeout(function() {
        resolve(data); 
    }, pause);
  });
}

var test = function(query, pause) {
  loadData(query, pause)
  .then(function(data) {
      console.log("got back test data", data);
      testDiv.innerHTML = data;
  });
};

test("first", 1000);
test("second", 0);
<div id="test">
</div>

【问题讨论】:

  • "那么界面将使用不正确的数据进行更新" 我不知道角度,但你确定吗?看起来很傻,因为回调直接链接到请求。这就是承诺的用途,不是吗?
  • @Kevin 我在 vanilla javascript 中添加了一个 jsfiddle 来说明这个问题。
  • @Igor 谢谢。我听说过 bluebird,但不想使用外部库。那篇文章还包括我将使用的 vanilla js 解决方案。
  • 解决 _httpTimeout 在这个流程中似乎没问题。

标签: javascript angularjs asynchronous


【解决方案1】:

一种解决方案是将第二个调用与第一个调用链接起来:

function test(query, pause) {
  return loadData(query, pause)
  .then(function(data) {
      console.log("got back test data", data);
      testDiv.innerHTML = data;
      return data;
  });
}

test("first", 1000)
  .then(function(data) {
    return test("second", 0);
});

.then 方法返回一个新的 Promise,它通过 successCallbackerrorCallback 的返回值被解析或拒绝(除非该值是一个 Promise,在这种情况下,它使用已解析的值解析在那个承诺中使用promise chaining

【讨论】:

  • 这是一个有趣的想法。在某些情况下这会很有用,但在这种特定情况下,我宁愿取消第一个承诺,而不是阻止它。
【解决方案2】:

此解决方案是为了避免可能创建的长承诺链 如果链变得像链中的 15 个承诺一样长,则会出现问题。

请检查同步队列的解决方案。使用syncArray,实现了同步队列。如果有任何异步请求处于挂起状态,则它只是将请求放入队列并根据先到先服务进行处理。

如果没有从以下行处理队列中的项目,则以下行将其推送到队列中 队列请求:

if(!isProcessFromQueue) {
    syncArray.push({query:query, pause:pause});
}

如果一个请求已经在进行中,那么它会休眠 1 秒,然后 再次从队列中调用处理。

if(isRunning) {
    setTimeout(function() {
    test(null, null, true);   
    }, 1000);
    return;
  }

然后,如果队列为空,则返回:

if(syncArray.length < 1) {
    return;
}

最后,在异步请求完成时,如果队列不为空, 然后再次请求从队列中处理并将isRunning 设置为 false 通知之前的请求已完成:

  isRunning = false;
  if(syncArray.length > 0) {
   test(null, null, true);
  }

完整的sn-p代码如下:

var testDiv = document.getElementById('test');

function loadData(query, pause) {
   var data = query;

   return new Promise((resolve, reject) => {
    setTimeout(function() {
        resolve(data); 
    }, pause);
  });
}
var syncArray = [];
var concatData = "";
var isRunning = false;
var test = function(query, pause, isProcessFromQueue) {
  
  if(!isProcessFromQueue) {
    syncArray.push({query:query, pause:pause});
  }
  
  if(isRunning) {
    setTimeout(function() {
    test(null, null, true);   
    }, 1000);
    return;
  }
  if(syncArray.length < 1) {
    return;
  }
  var popedItem = syncArray.shift();
  isRunning = true;
  loadData(popedItem.query, popedItem.pause)
  .then(function(data) {
      console.log("got back test data", data);
      concatData = concatData + "<br>" + data;
      testDiv.innerHTML = concatData;
      isRunning = false;
      if(syncArray.length > 0) {
       test(null, null, true);
      }
      
  });
};

test("first", 1000, false);
test("second", 0, false);
test("third", 500, false);
test("forth", 0, false);
<div id="test">
</div>

最后,当前的Promise 实现不能取消承诺。取消选项将在以后的版本中添加。 要实现它,您可以使用第三方库bluebird。这 Promise.race 可用于某些情况。

Promise.race 的实现如下:

var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, 'one'); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, 'two'); 
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 2011-01-31
    相关资源
    最近更新 更多