【问题标题】:How can I run the same promise again depending on the result from the previous run?如何根据上一次运行的结果再次运行相同的承诺?
【发布时间】:2018-05-27 12:54:25
【问题描述】:

我有一些包含在promise 中的代码。此代码将编辑远程数据库中的一些记录,并返回已编辑记录的数量。如果编辑的记录数大于0(即,一些工作已经完成),那么我想一次又一次地运行相同的方法,直到我得到一个0(即不再需要记录)编辑)。

我尝试了一些不同的方法,但它们都不会终止(即未调用解析)或者它们无法正常运行。

我尝试的第一个版本:

const doEdits = () => {
  return new Promise((resolve, reject) => {
    someDB.performEdits()
    .then(count => {
      if (count > 0) {
        doEdits()
      } else {
        resolve()
      }
    })
    .catch(reject)
  })
}

return new Promise((resolve, reject) => {
  someDB.init()
  .then(doEdits)
  .catch(reject)
})

我试过的第二个版本:

const doEdits = () => {
  return new Promise((resolve, reject) => {
    someDB.performEdits()
    .then(count => {
      resolve(count)
    })
    .catch(reject)
  })
}

return new Promise((resolve, reject) => {
  someDB.init()
  .then(doEdits)
  .then(count => {
    if (count > 0 ) {
      return doEdits()   // 'doEdits()' did not work...
    } else {
      resolve()
    }
  })
  .catch(reject)
})

欢迎提出任何建议。

【问题讨论】:

  • 您在doEdits 之后没有解析。 Promise 的结尾总是需要 resolvedrejected
  • @ErikKralj,如果您在谈论第一个示例,然后在if (count > 0) 之后,那么我需要在它之后执行.then(...) 并检查返回的结果并再次执行再等等……

标签: javascript node.js loops recursion promise


【解决方案1】:

不要做意大利面

您确实不需要创建一堆承诺,尤其是因为您使用的底层库已经返回了一个承诺。这种方法应该可以实现您的目标,而无需所有额外的调味料:

const doEdits = count => {
  if(count > 0) {
    return someDB.performEdits().then(doEdits);
  }
};

return someDB.init()
  .then(() => {
    performEdits().then(doEdits)
  });

这会将来自后续数据库调用的承诺链接到第一个承诺。任何后续的thens(和catches)都将对返回的promise进行操作(即等待它解析或拒绝),在传递给它们之前,它可能会在解析时被新的promise替换。


为什么您的代码不起作用

一旦你决定要实例化一个 Promise,你就承担了处理 resolve 和 reject 回调的责任 - 并且把自己交给了回调地狱。正是 Promise 应该解决的问题。

在两个 sn-ps 中,一旦你看到 count > 0 并调用 doEdits,你就会放弃之前的 Promise,实例化一个新的 Promise,最后在你的唤醒。您需要将 resolve 和 reject 函数传递到新的 Promise 中,并确保在新的 Promise 解决或拒绝时,它们会被适当地解决或拒绝。

不要这样做

function doEdits(previousPromise) {
  someDB.performEdits()
  .then((count) => {
    if(count > 0) {
      doEdits(this);
    } else {
      resolve();
    }
  })
};

return new Promise((resolve, reject) => {
  someDB.init()
  .then(() => {
    someDB.performEdits()
    .then((count) => {
      if(count > 0) {
        doEdits(this);
      } else {
        resolve();
      }
    })
  })
});

因为它很浪费,而且如果 performEdits 迭代 33 拒绝,也不会处理这种情况。从理论上讲,这可能会奏效,但推理起来要困难得多。

【讨论】:

    【解决方案2】:

    是的,您从未在 if 分支中调用 resolve。但是你不应该在这里使用resolve 函数,避免使用Promise constructor antipattern!做吧

    function doEdits() {
      return someDB.performEdits().then(count => {
        if (count > 0) {
          return doEdits();
        } else {
          return undefined; // ???
        }
      });
    }
    
    return someDB.init().then(doEdits);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      相关资源
      最近更新 更多