1

I am confused why this code returns an array of promises, while the last bit returns actual data (array of objects):

    ( async() => {
    		const [user, posts] = await Promise.all([
    			fetch('https://jsonplaceholder.typicode.com/users'),
    			fetch('https://jsonplaceholder.typicode.com/posts')
    		]).then( ([res,res2]) =>  [res.json(),res2.json()] 
    		).then( ([d1,d2]) => { 
    			console.log(d1,d2);
    	});
    })();
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Array(10)} 
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Array(100)}

When I use fetch by itself, I get the data I want:

fetch('https://jsonplaceholder.typicode.com/posts')
	.then( (res) => res.json() )
	.then( (data) => console.log(data));  // returns array of objects

// (100) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, ...

2 Answers 2

3

res.json() returns another promise so you have to either return that promise in a promise chain or use await or .then() on that promise. Because you're using [res.json(), res2.json()] as the return value in the promise chain, you are hiding promises in that array so they are not awaited by the promise chain at all. The promises themselves become the return result and thus Promise.all() doesn't know they are there and does not wait for them.

I would suggest chain each res.json() to its own parent:

( async() => {
        const [user, posts] = await Promise.all([
            fetch('https://jsonplaceholder.typicode.com/users').then(res => res.json()),
            fetch('https://jsonplaceholder.typicode.com/posts').then(res => res.json())
        ]);
        console.log(users, posts);
    });
})();

Then, you're chaining each res.json() directly to its source promises which Promise.all() will then await for you.

FYI, I don't see any reason to use async/await here at all as you can just do this:

    Promise.all([
        fetch('https://jsonplaceholder.typicode.com/users').then(res => res.json()),
        fetch('https://jsonplaceholder.typicode.com/posts').then(res => res.json())
    ]).then( ([users,posts]) => { 
            console.log(users, posts);
    });

FYI, it sure seems like a simple helper function would be useful too:

 function fetchJSON(req) {
     return fetch(req).then(res => res.json());
 }

Then, you could just do:

Promise.all([
    fetchJSON('https://jsonplaceholder.typicode.com/users'),
    fetchJSON('https://jsonplaceholder.typicode.com/posts')
]).then( ([users,posts]) => { 
        console.log(users, posts);
});

And, you probably want error handling with all of these options so you see errors. You can either use a .catch() or surround your await with try/catch.

Sign up to request clarification or add additional context in comments.

3 Comments

This makes perfect sense @jfriend00. Thank you. I saw this example in "JavaScript hacks for ES6 hipsters" at hackernoon.com/javascript-hacks-for-es6-hipsters-67d633ce8ace and thought I'd try. One quick note though. this code is now returning "Uncaught (in promise) TypeError: (intermediate value) is not iterable"
The one you provided above.
@rsilva - There are four different code blocks above. Is the issue with ([users,posts])? Or what exact line?
2

The problem is that an array and not a promise is returned in .then( ([res,res2]) => [res.json(),res2.json()], because json() response method returns another promise. This results in an array of promises in next then.

It should be

async () => {
    const [user, posts] = await Promise.all([
        fetch('https://jsonplaceholder.typicode.com/users'),
        fetch('https://jsonplaceholder.typicode.com/posts')
    ]).then(responses =>
         Promise.all(responses.map(response => response.json()))
    );

    console.log(user, posts);
}

Notice that adding another .then( ([d1,d2]) => { console.log(d1,d2) }) is unnecessary and also results in error because awaited value is undefined.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.