0

I have an array, said arr, and I need to iterate on it.

What I tried so far :

arr.forEach((rack) => {
    request.post({
        headers: {'content-type' : 'application/x-www-form-urlencoded'},
        url:     'https://example.com/render',
        body: "target=foobar"
    }, function(error, response, data){
        if (error) {
            console.err(error);
        } else {
            console.log(JSON.stringify(data, null, 4));
        }
    });
});

I have no output, nor error.

Bonus question: Can I return a value from within the post in the global scope ?

3 Answers3

1

The first part of your question is because request is asynchronous, you complete the forEach loop and exit before the call is complete.

As for the second part, you can use promises to basically await the result of your query. The code

function getPromise(url) {
    return new Promise((resolve, reject) => {
        request.post({
            headers: {'content-type' : 'application/x-www-form-urlencoded'},
            url:     'https://example.com/render',
            body: "target=foobar"
            }, function(error, response, data) {
                if(error) {
                    reject(error)
                } else {
                    resolve(JSON.stringify(data, null, 4))
                }
            })
        })        
}

var promiseArray = arr.map((rack) => getPromise(rack))
Promise.all(promiseArray).then((value) => {
    console.log('I am done');
})

Would be what you want. You can assign back to the global scope value (though it's not recommended)

Eric Yang
  • 2,678
  • 1
  • 12
  • 18
1

A solution would be to wrap it in a promise:

for rack of arr {
    try {
        const result = await new Promise((res, rej) => {
            request.post({
                headers: {'content-type' : 'application/x-www-form-urlencoded'},
                url:     'https://example.com/render',
                body: "target=foobar"
            }, function(error, response, data){
                if (error) {
                    rej(error);
                    console.err(error);
                } else {
                    res(data);
                }
            });
        });
        console.log(JSON.stringify(result, null, 4));
    } catch(err) {
        console.log(err);
    }
}
Tvde1
  • 1,246
  • 3
  • 21
  • 41
1

forEach is strictly synchronous and is generally obsolete because it doesn't support generators and async..await while loop statements do. This can be done with async..await and request-promise, which is official promisified counterpart to request:

// within async function
for (const rack of arr) {
    try {
        const data = await request.post({
            headers: {'content-type' : 'application/x-www-form-urlencoded'},
            url:     'https://example.com/render',
            body: "target=foobar"
        });
        console.log(JSON.stringify(data, null, 4));
    } catch (error) {
        console.err(error);
    }
}

Since requests don't depend on each other, they could be performed in parallel with Promise.all.

Can I return a value from within the post in the global scope ?

This is a special case of this infamous problem. A value from asynchronous call cannot be consumed in synchronous manner, this extends asynchronous control flow to all call stack, possibly up to entry point:

(async () => {
  const result = await asyncFn();
})().catch(console.error)
Estus Flask
  • 206,104
  • 70
  • 425
  • 565