I'm building a silly music quiz game for learning. I need to populate my view with related music from deezer api.
What I need:
- Get a random genre
- Get 5 artist from this genre (id + name)
- Get 1 music from each artist (name + link preview)
So, I found my way until step 3
But I can't find out how to properly send the same request 4 times (for each artist), and my reasearch gave me nothing so far
function deezer() { const reqGenero = new Request('); fetch(reqGenero) .then(response => { if (response.status === 200) { return response.json(); } else { throw new Error('Erro ao pegar gêneros'); } }) .then(generos => { /* pega genero aleatorio */ var generoId = generos.data[Math.floor(Math.random() * 10 + 1)].id; //console.log('\ngenero... ' + generoId); return fetch(' + generoId + '/artists') }) .then(response => { if (response.status === 200) { return response.json(); } else { throw new Error('Erro ao pegar artistas'); } }) .then(artistas => { /* 1 música de 4 artistas */ var artistasIds = []; for(var i = 0; i <= 4; i++) { artistasIds.push(artistas.data[i].id); console.log('\nId: ' + artistasIds[i]); // CAN I SEND THIS REQUEST 4 TIMES? return fetch(' + ids + '/top'); } }) .catch(error => { console.error(error); }); } *Pleade let me know if I'm doing something really wrong
4 Answers
If using promises explicitly (see below for async functions), I'd probably approach it like this; see *** comments for explanation:
// *** Give yourself a helper function so you don't repeat this logic over and over function fetchJson(errmsg, ...args) { return fetch(...args) .then(response => { if (!response.ok) { // *** .ok is simpler than .status == 200 throw new Error(errmsg); } return response.json(); }); } function deezer() { // *** Not sure why you're using Request here? const reqGenero = new Request('); fetchJson('Erro ao pegar gêneros', reqGenero) .then(generos => { /* pega genero aleatorio */ var generoId = generos.data[Math.floor(Math.random() * 10 + 1)].id; //console.log('\ngenero... ' + generoId); return fetchJson('Erro ao pegar artistas', ' + generoId + '/artists') }) .then(artistas => { /* 1 música de 4 artistas */ // *** Use Promise.all to wait for the four responses return Promise.all(artistas.data.slice(0, 4).map( entry => fetchJson('Erro ao pegar música', ' + entry.id + '/top') )); }) .then(musica => { // *** Use musica here, it's an array of the music responses }) .catch(error => { console.error(error); }); } That's assuming you want to use the results in deezer. If you want deezer to return the results (a promise of the four songs), then:
// *** Give yourself a helper function so you don't repeat this logic over and over function fetchJson(errmsg, ...args) { return fetch(...args) .then(response => { if (!response.ok) { // *** .ok is simpler than .status == 200 throw new Error(errmsg); } return response.json(); }); } function deezer() { const reqGenero = new Request('); return fetchJson('Erro ao pegar gêneros', reqGenero) // *** Note the return .then(generos => { /* pega genero aleatorio */ var generoId = generos.data[Math.floor(Math.random() * 10 + 1)].id; //console.log('\ngenero... ' + generoId); return fetchJson('Erro ao pegar artistas', ' + generoId + '/artists') }) .then(artistas => { /* 1 música de 4 artistas */ // *** Use Promise.all to wait for the four responses return Promise.all(artistas.data.slice(0, 4).map( entry => fetchJson('Erro ao pegar música', ' + entry.id + '/top') )); }); // *** No `then` using the results here, no `catch`; let the caller handle it } The async function version of that second one:
// *** Give yourself a helper function so you don't repeat this logic over and over async function fetchJson(errmsg, ...args) { const response = await fetch(...args) if (!response.ok) { // *** .ok is simpler than .status == 200 throw new Error(errmsg); } return response.json(); } async function deezer() { const reqGenero = new Request('); const generos = await fetchJson('Erro ao pegar gêneros', reqGenero); var generoId = generos.data[Math.floor(Math.random() * 10 + 1)].id; //console.log('\ngenero... ' + generoId); const artistas = await fetchJson('Erro ao pegar artistas', ' + generoId + '/artists'); /* 1 música de 4 artistas */ // *** Use Promise.all to wait for the four responses return Promise.all(artistas.data.slice(0, 4).map( entry => fetchJson('Erro ao pegar música', ' + entry.id + '/top') )); } 2You can replace the statement
// CAN I SEND THIS REQUEST 4 TIMES? return fetch(' + ids + '/top'); with
const fetchResults = []; artistasIds.forEach(function(ids){ fetchResults.push(fetch(' + ids + '/top')); }); return Promise.all(fetchResults); in then condition you'll get an array of values with top music from each artist. I haven't checked with the given API, but ideally it should work.
You can create 4 requests and wait for all of them to complete, using Promise#all.
.then(artistas => { /* 1 música de 4 artistas */ const artistasPromises = artistas.data.map(artista => fetch("" + artista.id + "/top").catch( err => ({ error: err }) ) ); return Promise.all(artistasPromises); }).then(musicList => { console.log(musicList); }); Notice the catch(). This makes sure that even if a fetch fails, the other fetch results are not ignored. This is because of the way Promise#all works. So, you need to iterate over musicList and check if there is any object of the shape { error: /* error object */ } and ignore that while processing the list.
Yes you can make 5 requests (not 4 its 0-4) and wait for each to complete. Use Array.prototype.map to create an array of request promises.(prefer over for- forEach and array.push)
and Promise.all to wait for all the promises to get complete, which will return the array of resolved responses, if no failures.
.then(artistas => { /* 1 música de 4 artistas */ var artistasIds = []; let ids = artistas.data.map(artist => artist.id).slice(0, 4); requests = ids.map(id => fetch(`)); return Promise.all(requests); } })