可以链接 '.then() 的返回响应,顺序与 '.then()' 的顺序不同

Can chained `.then()`s return responses in a different order than order of `.then()`s?

本文关键字:顺序 then 响应 链接 返回      更新时间:2023-09-26

在下面的示例中,服务器对doSomethingOne请求的响应是否有可能在服务器响应doSomethingTwo的请求之前返回?

$scope.pace = $interval (
    function() {
        // code
    }, 1000, 10
).then(postResult)
    .then(doSomethingOne)
        .then(doSomethingTwo);

问题是,doSomethingOne将数据发布到数据库,然后doSomethingTwo查询数据库并返回一些数据,包括doSomethingOne应该发布的数据。

但是对doSomethingTwo请求的响应不包括doSomethingOne发布的最新数据(直到$scope.pace从头开始再次运行(。

我对回调没有很强的理解(尽管有很多关于它们的阅读(,所以任何建议将不胜感激。

简要说明

doSomthingOne做一个$http.post()doSomethingTwo做一个$http.get()。这里没有使用任何承诺。

更新

从您的编辑:

doSomthingOne 做一个 $http.post((,doSomethingTwo 做一个 $http.get((。这里没有使用任何承诺。

好吧,$http.post返回一个承诺(有时在文档中称为"未来"(,但是如果您不使用它,那么没有什么可以阻止在 POST 完成之前调用doSomethingTwo。事实上,它很可能在 POST 完成之前(很久以前(被调用。

您可能只需返回承诺$http.post返回即可解决问题(如果您正在使用承诺,则返回由调用该承诺创建的承诺(。 例如:

function doSomethingOne() {
    return $http.post(/*...args...*/);
}

function doSomethingOne() {
    return $http.post(/*...args...*/).then(/*...*/);
}

详情如下。

原始答案(仍然相关(:

这取决于doSomethingOne做什么以及它返回什么。如果doSomethingOne启动异步进程,但没有返回该进程的承诺,则可以在该进程完成之前调用doSomethingTwo。如果doSomethingOne同步完成其工作(鉴于您所说的不太可能(或为其异步工作返回承诺,它将在调用doSomethingTwo之前完成,因为doSomethingTwo等待该承诺得到解决。

下面是一个示例,其中 doSomethingOne 不会为其异步工作返回承诺,因此doSomethingTwo可能会在 doSomethingOne 的异步工作完成之前运行:

// Simulate an asynchronous DB call
function dbCall(data) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve("Result for " + data);
    }, Math.floor(Math.random() * 500));
  })
}
function start() {
  console.log("start called");
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("start resolving");
      resolve();
    }, 0);
  })
}
function doSomethingOne() {
  // THIS IS PROBABLY WRONG
  console.log("doSomethingOne called");
  dbCall("one data").then(function(result) {
    console.log("doSometingOne's async is done");
  });
}
function doSomethingTwo() {
  console.log("doSomethingTwo called");
}
start().then(doSomethingOne).then(doSomethingTwo);

Babel's REPL 上的实时副本

这可能是错误的。相反,您希望doSomethingOne从其异步工作中返回承诺;它可以通过返回其调用的结果来做到这一点 dbCall(...).then

// Simulate an asynchronous DB call
function dbCall(data) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve("Result for " + data);
    }, Math.floor(Math.random() * 500));
  })
}
function start() {
  console.log("start called");
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("start resolving");
      resolve();
    }, 0);
  })
}
function doSomethingOne() {
  console.log("doSomethingOne called");
  return dbCall("one data").then(function(result) {
//^^^^^^^------------------------------------------- change is here
    console.log("doSometingOne's async is done");
  });
}
function doSomethingTwo() {
  console.log("doSomethingTwo called");
}
start().then(doSomethingOne).then(doSomethingTwo);

Babel's REPL 上的实时副本