Node承诺不会推送对数组

时间:2017-07-18 07:34:43

标签: javascript node.js ecmascript-6 promise es6-promise

我正在使用AWS Node SDK执行以下任务 -

  1. 获取区域
  2. 获取每个区域的群集ARN
  3. 获取ECS群集的过滤列表。
  4. 获取已过滤群集的服务
  5. 我要解开的部分是第4步,列出了每个群集的服务。基本上每个群集调用列表服务,每个响应只能返回10个项目,因此递归调用该函数以查看是否有另一个页面令牌退出。每个响应都被推送到一个数组。然后有一个最终的Promise.all打印出所有的回复。问题是只捕获了初始调用,而不是下一个令牌的任何递归调用。任何帮助将不胜感激:))

    function getLiveCluster() {
    
      var liveClusterName = 'xx1-app-ecs'
    
      // Filter out the required clusters
      clustersAry.forEach(function(cluster) {
        if (cluster && cluster.clusterArns && cluster.clusterArns.length > 0) {
          cluster.clusterArns.forEach(function(clusterArns) {
            if (clusterArns.indexOf(liveClusterName) > -1) {
    
              var serviceParams = {
                cluster: clusterArns,
                maxResults: 10,
                nextToken: ''
              };
    
              ecsRegionParams.region = cluster.RegionName;
              ecs = new aws.ECS(ecsRegionParams);
              getClusterServices(serviceParams)
            }
          });
        }
      });
    
      Promise.all(promiseAry2).then(() => {
        console.log('All services <<<<<<<<<<<<\n', serviceAry)
      });
    }
    
    function getClusterServices(serviceParams) {
    
      promiseAry2.push(ecs.listServices(serviceParams).promise().then(function(data) {
    
        serviceAry.push({
          cluster: serviceParams.cluster,
          service: data.serviceArns
        });
    
        if (data.nextToken) {
          serviceParams.nextToken = data.nextToken;
          getClusterServices(serviceParams)
        }
      }).catch((err) => {}));
    }
    

    编辑1

    在调试Promise.all数组之后,仍有待许可的承诺,如此处所示 -

    "> All promiseAry2 <<<<<<<<<<<<
     [ Promise { undefined },
      Promise { undefined },
      Promise { undefined },
      Promise { undefined },
      Promise { undefined },
      Promise { undefined },
      Promise { undefined },
      Promise { <pending> },
      Promise { <pending> },
      Promise { <pending> },
      Promise { <pending> } ]"
    

    如何确保承诺完成的任何想法?

    回答1回复

    谢谢 - 这是一段代码,只需一个小小的调整就可以了。需要重置ECS的区域,如此处所示 -

    // Reset ECS to current cluster region
    ecsRegionParams.region = cluster.RegionName;
    
    // Store the request for this cluster as a promise
    promiseAry.push(
        getClusterServices(
            new aws.ECS(ecsRegionParams),
            serviceParams
        )
    )
    

    新输出将数据传回到单独的对象中,如此处所示 -

    All arrayOfarraysOfServices <<<<<<<<<<<<
    [ [ { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-1',
    service: 
    [ 'arn:aws:ecs:eu-central-1:0123456789:service/service-1',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-2',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-3',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-4',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-5',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-6',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-7',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-8',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-9',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-10' ] },
    { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-1',
    service: 
    [ 'arn:aws:ecs:eu-central-1:0123456789:service/service-11',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-12' ] } ],
    [ { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-2',
    service: 
    [ 'arn:aws:ecs:eu-central-1:0123456789:service/service-1',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-2',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-3',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-4',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-5',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-6',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-7',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-8',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-9',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-10' ] },
    { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-2',
    service: 
    [ 'arn:aws:ecs:eu-central-1:0123456789:service/service-11',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-12' ] } ],
    [ { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-3',
    service: 
    [ 'arn:aws:ecs:eu-central-1:0123456789:service/service-1',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-2',
    'arn:aws:ecs:eu-central-1:0123456789:service/service-3' ] } ],
    [ { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-4',
    service: [] } ],
    [ { cluster: 'arn:aws:ecs:eu-central-1:0123456789:cluster/xx1-app-ecs-ECSCluster-5',
    service: [] } ]]
    

    我接下来要做的是过滤推送,这样如果群集arn已经存在,那么数据会连接到现有条目。

    EG Cluster arn:aws:ecs:eu-central-1:0123456789:cluster / xx1-app-ecs-ECSCluster-1有12个服务,而不是有2个对象,它将拥有12个服务。< / p>

    在函数getClusterServices中执行此操作是否明智,或者在Promise.all中完成所有承诺之后是否应该这样做?

    编辑2

    这是一个解决方案,将数组数组转换回单个数组,查找重复项,将重复的集群服务附加到当前集群服务,然后删除重复...生成最终的分页集群服务数组。

    Promise.all(promiseAry).then((arrayOfarraysOfServices) => {
    
        // Consolidate data into singular array
        var singularAry = [];
    
        // Recursively print array of unknown dimensions
        function morphToSingularArray(arr) {
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] instanceof Array) {
                    morphToSingularArray(arr[i]);
                } else {
                    singularAry.push(arr[i]);
                }
            }
            return singularAry;
        }
    
        var listAry = morphToSingularArray(arrayOfarraysOfServices);
    
        // Merge services for duplicate clusters
        // First cluster in array
        for (var i = 0; i < listAry.length; ++i) {
            // Second cluster in array
            for (var j = i + 1; j < listAry.length; ++j) {
                // Matching
                if (listAry[i].cluster === listAry[j].cluster) {
                    // Does service object exist
                    if (listAry[j].service && listAry[j].service.length > 0) {
                        var serviceAry = listAry[j].service;
                        // Iterate over second cluster services, appending to first cluster services
                        for (var x = 0; x < serviceAry.length; ++x) {
                            listAry[i].service.push(serviceAry[x]);
                        }
                    }
                    // Delete second cluster after appending
                    listAry.splice(j--, 1);
                }
            }
        }
        console.log('Paginated data array\n', listAry)
    
    }).catch((e) => console.log(e));
    

    可以将map用作上述三重数组解决方案的清洁方法吗?

1 个答案:

答案 0 :(得分:1)

这是你的问题,你将promises传递给promises数组,然后你将每个promises本身可能会在数组传递到Promise.all之后将更多的promise推送到同一个数组中。

在全局维护所有数据的同时在这样的回调中创建承诺是一个已知的anti-pattern with promises

Promise解析为一个值并且可以链接,这意味着我们通常可以通过它们传播它们的结果,而不是拥有全局数据。

对我来说,对于clustersAry中的每个元素,您都希望获得其服务(如果存在),并且每个服务都以递归方式获取其服务等。

您应该让getClusterServices本身返回一个承诺,该承诺将解析为通过递归级别收集的一系列服务。

这是基于以上评论的一种方法:

function getLiveCluster() {

  const liveClusterName = 'xx1-app-ecs'

  // Filter out the required clusters
  clustersAry.forEach(cluster => {
    if (cluster && cluster.clusterArns && cluster.clusterArns.length > 0) {
      cluster.clusterArns.forEach(clusterArns => {
        if (clusterArns.indexOf(liveClusterName) > -1) {
          const serviceParams = {
            cluster: clusterArns,
            maxResults: 10,
            nextToken: ''
          };

          // store the request for this cluster as a promise
          promiseAry.push(
            getClusterServices(
              new aws.ECS(cluster.RegionName),
              serviceParams
            )
          )
        }
      });
    }
  });

  Promise.all(promiseAry).then((arrayOfarraysOfServices) => {
    console.log('All services <<<<<<<<<<<<\n', arrayOfarraysOfServices)
  });
}

function getClusterServices(ecs, serviceParams, clusterServiceAry = []) {
  // return a promise here that resolves 
  // with an array of services for the given serviceParams
  // once all recursive service requests are finished
  return ecs
    .listServices(serviceParams)
    .promise()
    .then(data => {
      clusterServiceAry.push({
        cluster: serviceParams.cluster,
        service: data.serviceArns
      });

      return !data.nextToken
        ? clusterServiceAry  // nextToken is falsy, we are finished, resolve with the service array
        : getClusterServices(
            ecs,
            // update the token by creating a new object
            // rather than mutating the existing one
            Object.assign(
              {},
              serviceParams,
              {
                nextToken: data.nextToken
              }
            ),
            // pass the cluster service array so we can accumulate
            // the services
            clusterServiceAry
          )
      })
}