【问题标题】:How can I build a repeating Promise .then clause? [duplicate]如何构建重复的 Promise .then 子句? [复制]
【发布时间】:2018-09-21 18:45:45
【问题描述】:

如何将.then 子句作为循环重复?我需要等待 .then 子句承诺解决,然后如果没有满足退出条件,我需要再次重复相同的操作......直到满足退出条件。

我的用例是对多个“页面”数据重复 ajax GET 调用,直到检索到所有数据。

我可以按如下方式简化和模拟问题。这是我想.thenRepeat 的 .then 子句:

  .then(function(retData) {
      namesList.push.apply(namesList, retData); // accum data into list
      queryParms.pageNo++;                      // set to next page
      return pretendAjaxFnc(queryParms);        // get next page
  })

这是一个可运行的例子:

function pretendAjaxFnc(obj) {
  return Promise.resolve().then(function() {
    if (obj.pageNo < 6) { // create a pretend "I'm done" point.
      // return a couple dummy records
      return [{  fld1: "data1",  fld2: "data2" }, 
              {  fld1: "data1",  fld2: "data2" }];
    } else {
      // this is the exit criteria
      // It will actually be 404 http status converted to a custom exception
      throw new Error("NO-MORE-DATA");
    }
  });
};

function clientAccumulator() {
  var namesList = [];
  var queryParms = {
    pageNo: 1
  };

  return pretendAjaxFnc(queryParms)
    .then(function(retData) {
      namesList.push.apply(namesList, retData); // append data to list
      queryParms.pageNo++; // set to get next page
      console.log("EIC.GTEST11 list.len: ", namesList.length);
      return pretendAjaxFnc(queryParms);
    })
    // repeat until some exit criteria - like an exception
    .then(function(retData) {
      namesList.push.apply(namesList, retData);
      queryParms.pageNo++;
      console.log("EIC.GTEST21 list.len: ", namesList.length);
      return pretendAjaxFnc(queryParms);
    })
    // repeat until some exit criteria - like an exception
    .then(function(retData) {
      namesList.push.apply(namesList, retData);
      queryParms.pageNo++;
      console.log("EIC.GTEST31 list.len: ", namesList.length);
      return pretendAjaxFnc(queryParms);
    })
    // repeat until some exit criteria - like an exception
    // ...
    .catch(function(ex) {
      if (ex.message === "NO-MORE-DATA") {
        return namesList;
      } else {
        throw ex;
      }
    });
};

clientAccumulator(); // Run the function

这是需要在当前 iOS/Safari 和 Firefox 上运行的浏览器代码(尽管最好有更多变体)。我正在使用 AngularJS,但我相信我已经删除了任何这种特殊性。

有人有.thenRepeat 可以指点我吗?

【问题讨论】:

  • 也许await 是你的朋友,如果你能够使用它(无论是原生还是 babel)?
  • while 循环中使用await 也可以,是的..
  • await - 是的,好主意。

标签: javascript promise


【解决方案1】:

递归是你的朋友。

再次阅读后,似乎这可能是您要寻找的更多内容:

repeatPromiseUntil({
    promiseMethod,
    doneConditionMethod,
    waitInterval = 100
}){
    return promiseMethod()
        .then((result) => {
            if (doneConditionMethod(result)) {
                return this.$q.resolve(result);
            }

            return this.$timeout(waitInterval)
                .then(() => this.repeatPromiseUntil({promiseMethod, doneConditionMethod, waitInterval}));
        });
}

这是我自己的代码中的一个示例(它是从 Typescript 重写的,因此可能有一两个错字)

function retryPromise({
    maxRetries,
    promiseMethod,
    successConditionMethod,
    retryInterval,
    increaseInterval = true
}) {
    if (increaseInterval) {
        retryInterval = retryInterval + 1000;
    }

    return promiseMethod().then((result) => {
        if (successConditionMethod(result)) {
            return $q.resolve(result);
        } else if (maxRetries > 0) {
            return $timeout(retryInterval)
                .then(() => {
                    return retryPromise({
                        maxRetries: maxRetries - 1,
                        promiseMethod,
                        successConditionMethod,
                        retryInterval,
                        increaseInterval
                    });
                });
        } else {
            retryInterval = 0;
            return $q.reject();
        }
    });
}

编辑:我添加了一些我自己使用过的角度细节(最初错过了关于角度的评论)

【讨论】:

    【解决方案2】:

    只要把then链放到一个函数中,就可以递归了:

      function recurse() {
        return pretendAjaxFnc(queryParams)
          .then(function(retData) {
             namesList.push(...retData);
             queryParms.pageNo++;
             return recurse();
        });
     }
    

    工作示例:

    function pretendAjaxFnc(obj) {
      return Promise.resolve().then(function() {
        if (obj.pageNo < 6) { // create a pretend "I'm done" point.
          // return a couple dummy records
          return [{  fld1: "data1", fld2: "data2" }, 
                  {  fld1: "data1", fld2: "data2" }];
        } else {
          // this is the exit criteria
          // It will actually be 404 http status converted to a custom exception
          throw new Error("NO-MORE-DATA");
        }
      });
    };
    
    function clientAccumulator2() {
      var namesList = [];
      var queryParms = {
        pageNo: 1
      };
      console.log("TEST00 list.len: ", namesList.length);
    
      function recurse() {
        return pretendAjaxFnc(queryParms)
          .then(function(retData) {
            namesList.push(...retData);
            console.log("TEST01 list.len: ", namesList.length);
            queryParms.pageNo++;
            return recurse();
          });
      }
    
      return recurse()
        // repeat until some exit criteria - like an exception
        .catch(function(ex) {
          if (ex.message === "NO-MORE-DATA") {
            return namesList;
          } else {
            throw ex;
          }
        });
    };
    clientAccumulator2(); // Run the function

    【讨论】:

    • 谢谢@JonasW,我喜欢你的回答。我对其进行了编辑,添加了一个工作示例。
    • @GaryL 很高兴为您提供帮助 :)
    猜你喜欢
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2017-12-30
    • 1970-01-01
    • 2014-07-19
    • 2015-07-06
    • 2015-12-12
    相关资源
    最近更新 更多