1

I'm filling an array inside a loop and I need the full array when the loop finishes.

I've tried handling everything through promises or by using a counter but i can't seem to figure out the trick here.

lambda.listFunctions({}).promise()
    .then((data) => {
        data.Functions.forEach(func => {
            lambda.listTags({ Resource: func.FunctionArn }).promise()
                .then((data) => {
                    if ("Edge" in data.Tags) {
                        available_functions.push(func.FunctionName)
                    }
                })
        });
          console.log(available_functions)
    })

available_functions is always empty unless I console log it at the end of each foreach loop and then I have it returning 18 times which is not what I want.

  • 2
    Can you use the `await` keyword? – Dai Feb 07 '19 at 23:58
  • I've tried it by making the anonymous function In the foreach asynchronous and using await but it doesn't slow this bad boy down, or at least I haven't been using it right – Sahm Samarghandi Feb 08 '19 at 00:03
  • @Dai See https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – jarmod Feb 08 '19 at 00:24
  • "I need the full array when the loop finishes" actually can't be done. You can construct an array of promises to supply data and use `Promise` all to proceed when all data has arrived, or remove the `forEach` loop and write an asynchronous loop and `await` individual proimises of data. In either case it is not possible to process data obtained synchronously with making requests for it. – traktor Feb 08 '19 at 00:35
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – traktor Feb 08 '19 at 00:37

2 Answers2

0

I believe you can just promise it chain it to ensure all operations within the scope of the then completes before going down the chain.

lambda.listFunctions({}).promise()
  .then(data => {
    const { Functions } = data;

    // I converted this from forEach to for of
    for (const func of Functions) {
      lambda.listTags({ Resource: func.FunctionArn }).promise()
        .then(data => {
          if ("Edge" in data.Tags) {
            available_functions.push(func.FunctionName)
          }
        })
    }
  // also you can promise chain it if available_functions is within scope
  })
  .then(() => console.log(available_functions))

Or the cleaner async await way would look something like...

async fn() {
  const available_functions = [];

  const { Functions } = await lambda.listFunctions({}).promise();

  for (const func of Functions) {
    const tags = await lambda.listTags({ Resource: func.FunctionArn }).promise();

    if ("Edge" in tags) {
      available_functions.push(func.FunctionName)
    }

  }

  return available_functions

}

Hope this helps!

mralanlee
  • 479
  • 5
  • 15
0

You can use Promise.all with your problem. See documentation on Promise.all().

const available_functions = [];

lambda.listFunctions({}).promise()
    .then((data) => {
        const promises = []; // Collect promises

        data.Functions.forEach(func => {
            promises.push(lambda.listTags({ Resource: func.FunctionArn }).promise()
                .then((data) => {
                    available_functions.push(func.FunctionName)
                    return Promise.resolve(available_functions);
                })
            );
        });

        Promise.all(promises)
            .then(results => {
                    console.log(available_functions)
                // or
                    console.log(results[results.length - 1]);
            });
    });
Alex Pappas
  • 2,377
  • 3
  • 24
  • 48