简体   繁体   中英

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.

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 syntax

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 await ing 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 await s on various things (rather than just on new Promise(...) ), that's different. :-)

Since it is async, the values have not been determined at the time map returns. They won't exist until the arrow function has been run.

This is why Promises exist. They are a promise of a value being available in the future.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM