I'm using only pure JS and HTML. No frameworks.
I'm fetching a few html files to my index.html. After they are all fetched I'd like to continue with the script. I'm tryint to figure out how to resolve this (I guess with Promises) but cannot make it work. How to wait for all of them to finish?
const prepareHead = fetch("../static/_includes/_head.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("head").innerHTML = data;
resolve();
});
const prepareHeader = fetch("../static/_includes/_header.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("header").innerHTML = data;
});
const prepareStaticLinks = fetch("../static/_includes/_static_links.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("static_links").innerHTML = data;
});
const prepareFooter = fetch("../static/_includes/_footer.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("footer").innerHTML = data;
});
await Promise.all([prepareHead, prepareHeader, prepareFooter, prepareStaticLinks]);
// next line should be called only after all files are fetched
console.log("document prepared");
but await Promise does not work:
Uncaught SyntaxError: await is only valid in async functions and async generators
What is the correct way to do this?
Try replacing
await Promise.all([prepareHead, prepareHeader, prepareFooter, prepareStaticLinks]);
console.log("document prepared");
with
Promise.all([prepareHead, prepareHeader, prepareFooter, prepareStaticLinks])
.then(() => {
console.log("document prepared")
});
Your other option would be to use await inside an async function, like so
const getData = async () => {
const prepareHead = fetch("../static/_includes/_head.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("head").innerHTML = data;
resolve();
});
const prepareHeader = fetch("../static/_includes/_header.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("header").innerHTML = data;
});
const prepareStaticLinks = fetch("../static/_includes/_static_links.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("static_links").innerHTML = data;
});
const prepareFooter = fetch("../static/_includes/_footer.html")
.then(response => {
return response.text()
})
.then(data => {
document.querySelector("footer").innerHTML = data;
});
await Promise.all([prepareHead, prepareHeader, prepareFooter, prepareStaticLinks]);
// next line should be called only after all files are fetched
console.log("document prepared");
};
getData();
Related
I'm working on a React project where I have a function that fetches paginated data recursively. This function is defined in another function, where I activate the loading screen with showLoading() at the start, where I'm calling the fetching data function in the body and deactivate the loading screen with hideLoading() at the end. The function:
const fetchPlaylist = (playlistId) => {
showLoading()
const getPlaylistDataRecursively = (url) => {
fetch('/spotify/get-track-ids', {headers: {
'url': url
}})
.then(response => response.json())
.then(data => {
console.log(data)
setTitles(data.title)
setArtists(data.artist)
setFeatures(data.features)
setIds(data.track_ids)
if (data.next_url) {
const next_url = data.next_url.replace('https://api.spotify.com/v1', '')
getPlaylistDataRecursively(next_url)
}
})
}
getPlaylistDataRecursively(`/playlists/${playlistId}/tracks/?offset=0&limit=100`)
hideLoading()
}
I believe I can attach a promise to the getPlaylistDataRecursively call with the then keyword but I'm getting a TypeError: Cannot read property 'then' of undefined. Probably because getPlaylistDataRecursively doesn't return anything. How do I make sure that hideLoading is called after getPlaylistDataRecursively is done?
You always need to return a promise.
const fetchPlaylist = (playlistId) => {
showLoading()
const getPlaylistDataRecursively = (url) => {
return fetch('/spotify/get-track-ids', {headers: {
'url': url
}})
.then(response => response.json())
.then(data => {
console.log(data)
setTitles(data.title)
setArtists(data.artist)
setFeatures(data.features)
setIds(data.track_ids)
if (data.next_url) {
const next_url = data.next_url.replace('https://api.spotify.com/v1', '')
return getPlaylistDataRecursively(next_url)
}
})
}
return getPlaylistDataRecursively(`/playlists/${playlistId}/tracks/?offset=0&limit=100`)
.then(() => hideLoading());
}
Or, using async/await:
const fetchPlaylist = async (playlistId) => {
showLoading()
const getPlaylistDataRecursively = async (url) => {
const response = await fetch('/spotify/get-track-ids', {headers: {
'url': url
}})
const data = response.json()
console.log(data)
setTitles(data.title)
setArtists(data.artist)
setFeatures(data.features)
setIds(data.track_ids)
if (data.next_url) {
const next_url = data.next_url.replace('https://api.spotify.com/v1', '')
await getPlaylistDataRecursively(next_url)
}
}
await getPlaylistDataRecursively(`/playlists/${playlistId}/tracks/?offset=0&limit=100`)
hideLoading()
}
I created an API using Flask, and it is working perfectly when using it in Postman, giving me JSON.
Anyways, when I try to fetch it in javascript, it is giving me undefined:
api = 'http://127.0.0.1:5000/';
const getData = () => {
fetch(api)
.then(response => {
response.json();
})
.then(data => {
console.log(data);
});
};
getData();
As I said, when I try to log the data, it prints
undefined
You need to return your json data(return response.json();), fixed snippet:
api = 'http://127.0.0.1:5000/';
const getData = () => {
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
console.log(data);
});
};
getData();
You get undefined because you dont return anything. Every function returns undefined if you dont return something.
api = 'http://127.0.0.1:5000/';
const getData = () => {
fetch(api)
.then(response =>{
return response.json();
})
.json() is asynchronous too so you will need an .then() block after ur function call.
getData().then( res => {
console.log(res);
});
Request to the api successfully return the data as expected. The data from api is saved to 'fact' variable. The problem is that the 'getData' function returns promise which is expected to resolve
the data, instead it returns undefined.
const getData = num => {
let fact;
if (Array.isArray(num)) {
fetch(`http://numbersapi.com/${num[0]}/${num[1]}/date`)
.then(response => response.text())
.then(data => {
fact = data;
});
} else if (num.math === true) {
fetch(`http://numbersapi.com/${num.val}/math`)
.then(response => response.text())
.then(data => {
fact = data;
});
} else {
fetch(`http://numbersapi.com/${num}`)
.then(response => response.text())
.then(data => {
fact = data;
});
}
return new Promise((resolve, reject) => {
resolve(fact);
});
};
getData([1, 26]).then(val => {
console.log(val);
});
Fetch is a promise based api, it returns a promiss, and you don't need to wrap fetch in promise.
You could prepare the url string in the if checks, and then use it in the fetch call.
Example
const getData = num => {
let url;
if (Array.isArray(num)) {
url = `http://numbersapi.com/${num[0]}/${num[1]}/date`;
} else if (num.math === true) {
url = `http://numbersapi.com/${num.val}/math`;
} else {
url = `http://numbersapi.com/${num}`
}
return fetch(url);
};
getData([1, 26]).then(response => {
console.log(response.text());
});
i'm trying to assign the variable countries to the response of the fetch api but when i print out countries i get undefined ? can anyone explain to me why ? and a solution if it is possible.
async function getCountries(url) {
const data = await fetch(url);
const response = await data.json();
return response;
}
let countries;
document.addEventListener('DOMContentLoaded', () => {
getCountries('https://restcountries.eu/rest/v2/all')
.then(res => countries = res)
.catch(err => console.log(err));
})
console.log(countries);
function getCountries(url) {
return new Promise((resolve,reject)=>{
fetch(url).then(res => {
//You can parse the countries from the api response here and return to the
//event listener function from here using the resolve methood call parameter
resolve(res);
})
.catch(err => console.log(err));
})
}
document.addEventListener('DOMContentLoaded', () => {
getCountries('https://restcountries.eu/rest/v2/all')
.then(res => {
//the returned value after api call and parsing will be available here in res
})
})
Or if you dont want another function for this one you can directly get it using the following way,
document.addEventListener('DOMContentLoaded', () => {
let countries;
fetch('https://restcountries.eu/rest/v2/all')
.then(res => {
//the returned value after api call and parsing out the countries hereit self
countries = res.data.countries;
})
})
app.js
import test from "./asyncTest";
test().then((result)=>{
//handle my result
});
asyncTest.js
const test = async cb => {
let data = await otherPromise();
let debounce = _.debounce(() => {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then( => response.json())
.then(json => json );
}, 2000);
};
export default test;
The fetch result "json" I intend to return is unable to be the return value of "test" function since the value only available in an inner function scope such as debounce wrapper. Since above reason, I tried to pass a callback function and wrap the callback to be Promise function(pTest) as below.
const test = async cb => {
let debounce = _.debounce(() => {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(json => cb(null, json))
.catch(err => cb(err));
}, 2000);
};
const pTest = cb => {
return new Promise((resolve, reject) => {
test((err, data) => {
if (err) reject(err);
resolve(data);
});
});
};
export default pTest;
This way works for me, but I'm wondering if it's correct or are there any ways to solve this scenario?
The fetch API already returns a promise. Wrapping it in another Promise object is actually an anti-pattern. it is as simple as the code below:
/*export*/ async function test() {
let data = await otherPromise();
return fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(json => {
return {
json: json,
data: data
}
});
};
function otherPromise() {
return new Promise((resolve, reject) => {
resolve('test for data value');
});
}
// In index.js call
test().then(res => {
console.log(res)
});