I am trying to fetch the HTML script of two webpages using their URLs. This is my code:
const links = ["url1" : "https://.......", "url2" : "https://......"];
var responses = [];
for(const [key,value] of Object.entries(links)){
let resp = fetch('https://api.codetabs.com/v1/proxy?quest='+value)
responses.push(resp);
}
Promise.all(responses)
.then( htmlfiles =>{
htmlfiles.forEach(file=>{
file.text().then(function(data){
gethtmldata(data);
})
})
})
In my function gethtmldata, I am parsing this data in HTML format:
function gethtmldata(html_data){
var parser = new DOMParser();
var htmldoc = parser.parseFromString(html_data, "text/html");
console.log(htmldoc); //shows data of url2, then url1
}
To my utter surprise, the data of url2 gets printed first, then url1. Why?
It should show the html data of url1 then url2. How do I fix this?
>Solution :
The iterations of your for loop aren’t paused when you do file.text().then(function(data){...}. Instead, your loop fires off multiple .text() calls which will complete sometime in the future, with no guaranteed order on which ones will complete first.
You should .push() a Promise that resolves to your .text() data instead when you create resp:
const links = {"url1" : "https://.......", "url2" : "https://......"};
const urls = Object.values(links);
const responses = [];
for(const value of urls){
const txtPromise = fetch('https://api.codetabs.com/v1/proxy?quest='+value).then(resp => resp.text());
responses.push(txtPromise);
}
Promise.all(responses)
.then(htmlData => {
htmlData.forEach(data=>{
gethtmldata(data);
});
});
You can refactor the above by using .map() and async/await like so:
async function fetchHTMLData(urls) {
const promises = urls.map(async url => {
const resp = await fetch('https://api.codetabs.com/v1/proxy?quest='+url);
return resp.text();
});
return Primise.all(promises);
};
async function processHTMLData() {
const links = {"url1" : "https://.......", "url2" : "https://......"};
const urls = Object.values(links);
const htmlArr = await fetchHTMLData(urls);
htmlArr.forEach(htmlStr => {
gethtmldata(htmlStr);
});
}