【问题标题】:Recursively calling asynchronous function that returns a promise递归调用返回承诺的异步函数
【发布时间】:2023-03-28 10:22:01
【问题描述】:

我正在尝试递归调用 AWS 的 SNS listEndpointsByPlatformApplication。这将返回前 100 个端点,然后返回 NextToken 中的令牌(如果还有更多要返回)(详细信息:AWS SNS listEndpointsByPlatformApplication)。

这是我尝试过的:

var getEndpoints = function(platformARN, token) {

  return new models.sequelize.Promise(function(resolve, reject) {
    var params = {
      PlatformApplicationArn: platformARNDev
    };
    if (token != null) {
      params['NextToken'] = token;
    }
    sns.listEndpointsByPlatformApplication(params, function(err, data) {
      if (err) {
        return reject(err);
      }
      else {
        endpoints = endpoints.concat(data.Endpoints); //save to global var
        if ('NextToken' in data) {
          //call recursively
          return getEndpoints(platformARN, data.NextToken);
        }
        else {
          console.log('trying to break out!');
          return resolve(true);          
        }
      }
    });
  });
}

我是这样称呼它的:

getEndpoints(platformARNDev, null)
.then(function(ret) {
  console.log('HERE!');
}, function(err) {
  console.log(err);
});

问题是:第一次调用发生,然后递归调用发生,我收到消息trying to break out!,但HERE! 永远不会被调用。我认为我的承诺的回报方式有问题。

感谢指点。

【问题讨论】:

    标签: javascript amazon-web-services recursion promise


    【解决方案1】:

    问题是您尝试解决/拒绝部分完成的查询。这是一个带有虚拟服务的完整工作示例。我将数据抓取封装到它自己的递归函数中,并且仅在我完全获取所有数据或偶然发现错误时才解析/拒绝:

    // This is the mock of the service. It yields data and token if
    // it has more data to show. Otherwise data and null as a token.
    var dummyData = [0, 1, 2, 3, 4];
    function dummyAsyncCall(token, callback) {
      token = token || 0;
      setTimeout(function() {
        callback({
            dummyDataPart: dummyData[token],
            token: (typeof (dummyData[token]) == 'undefined') ? null : (token + 1)
        });
      });
    }
    
    // Here is how you would recursively call it with promises:
    
    function getAllData() {
      //data accumulator is sitting within the function so it doesn't pollute the global namespace.
      var dataSoFar = [];
    
      function recursiveCall(token, resolve, reject) {
        dummyAsyncCall(token, function(data) {
          if (data.error) {
            reject(data.error);
          }
          if (!data.token) {
            //You don't need to return the resolve/reject result.
            resolve(dataSoFar);
          } else {
            dataSoFar = dataSoFar.concat(data.dummyDataPart);
            recursiveCall(data.token, resolve, reject);
          }
        });
      }
    
      return new Promise(function(resolve, reject) {
        // Note me passing resolve and reject into the recursive call.
        // I like it this way but you can just store them within the closure for
        // later use
        recursiveCall(null, resolve, reject);
      });
    }
    
    //Here is the call to the recursive service.
    getAllData().then(function(data) {
      console.log(data);
    });
    

    Fiddle with me

    【讨论】:

    • 好的 - 看起来很有希望 - 会试一试。
    • 非常适合我需要获取多个分页 json 并一次显示的用户脚本
    【解决方案2】:

    那是因为你不需要返回resolve/reject,只需在递归调用完成时调用resolve/reject。粗略的代码如下所示

    var getEndpoints = function(platformARN, token) {
    
      return new models.sequelize.Promise(function(resolve, reject) {
        var params = {
          PlatformApplicationArn: platformARNDev
        };
        if (token != null) {
          params['NextToken'] = token;
        }
        sns.listEndpointsByPlatformApplication(params, function(err, data) {
          if (err) {
            reject(err);
          }
          else {
            endpoints = endpoints.concat(data.Endpoints); //save to global var
            if ('NextToken' in data) {
              //call recursively
              getEndpoints(platformARN, data.NextToken).then(function () {
                resolve(true);
              }).catch(function (err) {
                reject(err);
              });
            }
            else {
              console.log('trying to break out!');
              resolve(true);          
            }
          }
        });
      });
    }
    

    注意:这只是一个粗略的代码,可能有效,也可能无效,但只是给出一个大致的想法)

    我在下面添加了一个代码 sn-p 来支持这个概念,并且效果很好,请查看。

    i = 0;
    
    $('#output').empty();
    
    function pro() {
      return new Promise(function(resolve, reject) {
        if (i > 3) {
          resolve();
          return;
        }
        window.setTimeout(function() {
          console.log(i);
          $('#output').append(i).append('<br/>');
          i += 1;
          pro().then(function() {
            resolve()
          }).catch(function() {
            reject()
          });
        }, 2000);
      });
    }
    
    pro().then(function () { $('#output').append("now here"); })
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    
    <div id="output"></div>

    【讨论】:

    • 嗨 - 我不认为是这样。我之前有没有returns 的代码。也刚刚重试 - 仍然是同样的问题
    • 但是javascript还是一样的语言,把$('#output').append换成console.log,还是一样的
    猜你喜欢
    • 2019-03-10
    • 2019-05-25
    • 1970-01-01
    • 2022-01-26
    • 2020-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    相关资源
    最近更新 更多