如何根据前一次运行的结果再次运行相同的承诺?

时间:2017-12-13 15:09:57

标签: javascript node.js loops recursion promise

我有一些包含在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)
})

欢迎提出任何建议。

2 个答案:

答案 0 :(得分:3)

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

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

return someDB.init().then(doEdits);

答案 1 :(得分:1)

不要制作意大利面

你真的不需要创建一堆承诺,特别是因为你正在使用的底层库已经给你一个承诺。这种方法应该完成你的目标,而不需要额外的补充:

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

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

这会将后续db调用的promise转换为第一个promise。任何后续的then s(和catch es将对返回的promise做出操作(即,等待它解析或拒绝),在传递给promise之前,它可能会被新的promise替换。它们。

为什么您的代码不起作用

一旦你决定要实例化Promise,你就承担了处理决心和拒绝回调的责任 - 并且让你自己回调地狱。正是Promise应该解决的问题。

在这两个片段中,只要您看到count > 0并调用doEdits,就会放弃之前的Promise,实例化一个新的Promise,最后得到一条un resolve的踪迹你承诺在你身后。您需要将解决方案和拒绝功能传递到新承诺中,并确保在新承诺解决或拒绝时适当地解决或拒绝这些功能。

不要这样做

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拒绝,也不处理这种情况。从理论上讲,这可能会奏效,但要推理起来要困难得多。