Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does async array map return promises, instead of values

See the code below

var arr = await [1,2,3,4,5].map(async (index) => { 
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index);
            console.log(index);
        }, 1000);
    });
});
console.log(arr); // <-- [Promise, Promise, Promise ....]
// i would expect it to return [1,2,3,4,5]

Quick edit: The accepted answer is correct, by saying that map doesnt do anything special to async functions. I dont know why i assumed it recognizes async fn and knows to await the response.

I was expecting something like this, perhaps.

Array.prototype.mapAsync = async function(callback) {
    arr = [];
    for (var i = 0; i < this.length; i++)
        arr.push(await callback(this[i], i, this));
    return arr;
};

var arr = await [1,2,3,4,5].mapAsync(async (index) => { 
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index);
            console.log(index);
        }, 1000);
    });
});
// outputs 1, 2 ,3 ... with 1 second intervals, 
// arr is [1,2,3,4,5] after 5 seconds.
like image 319
Rainer Plumer Avatar asked Jul 17 '26 09:07

Rainer Plumer


1 Answers

Because an async function always returns a promise; and map has no concept of asynchronicity, and no special handling for promises.

But you can readily wait for the result with Promise.all:

try {
    const results = await Promise.all(arr);
    // Use `results`, which will be an array
} catch (e) {
    // Handle error
}

Live Example:

var arr = [1,2,3,4,5].map(async (index) => { 
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index);
            console.log(index);
        }, 1000);
    });
});
(async() => {
    try {
        console.log(await Promise.all(arr));
        // Use `results`, which will be an array
    } catch (e) {
        // Handle error
    }
})();
.as-console-wrapper {
  max-height: 100% !important;
}

or using Promise callbacks:

Promise.all(arr)
    .then(results => {
        // Use `results`, which will be an array
    })
    .catch(err => {
        // Handle error
    });

Live Example:

var arr = [1,2,3,4,5].map(async (index) => { 
    return await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index);
            console.log(index);
        }, 1000);
    });
});
Promise.all(arr)
    .then(results => {
        console.log(results);
    })
    .catch(err => {
        // Handle error
    });
.as-console-wrapper {
  max-height: 100% !important;
}

Side note: Since async functions always return promises, and the only thing you're awaiting in your function is a promise you create, it doesn't make sense to use an async function here anyway. Just return the promise you're creating:

var arr = [1,2,3,4,5].map((index) => { 
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(index);
            console.log(index);
        }, 1000);
    });
});

Of course, if you're really doing something more interesting in there, with awaits on various things (rather than just on new Promise(...)), that's different. :-)

like image 122
T.J. Crowder Avatar answered Jul 19 '26 00:07

T.J. Crowder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!