Execute async request inside .map loop in correct order

1.5k views Asked by At

I'm struggling with .map loop and async function inside. I use request-promise for async requests.

  import * as rp from 'request-promise';

  const testArray = ['one', 'two', 'three'];
  const link = 'https://somelink.com/';

  const test = testArray.map(async (elem) => {
    console.log('before', elem);

    await rp.get(link)
      .then(async () => {
        console.log('success');
      });

    console.log('after', elem);
  });

  Promise.all(test);

The output of this code:

before one
before two
before three
success
after one
success
after three
success
after two

What I need is that the code to execute in the correct order with output like this:

before one
success
after one
before two
success
after two
before three
success
after three

Can't figure out what am I doing wrong. Please help.

1

There are 1 answers

2
jfriend00 On BEST ANSWER

.map() is NOT async aware. It will not pause its loop for an await in the callback function you pass it. Instead, the await will just immediately cause the async function to return an unresolved promise and the .map() will go right ahead with the other iterations of the loop. As you already seem to know the resulting array from .map() will just be an array of those promises.

If you want the loop to pause and wait for the await, so you can truly sequence your asynchronous operations, then use a plain for loop, not a .map() loop.

 import * as rp from 'request-promise';

  const testArray = ['one', 'two', 'three'];
  const link = 'https://somelink.com/';

  for (let elem of testArray) {
    console.log('before', elem);

    await rp.get(link)
      .then(async () => {
        console.log('success', elem);
      });

    console.log('after', elem);
  });

This will then execute your rp.get() operations in sequence waiting for the first one to complete before the second one is executed. Your .map() loop was executing them all in parallel which means you do not control the order of execution.


FYI, the request() library and the corresponding derivatives of it have been deprecated and will no longer be actively developed to add new features. There is a list of alternatives here that are recommended for all new projects. My favorite is got() which was built from the ground up to use promises, but you can pick whichever one has the features you want and/or an API you like.