Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Fetch API prints promise in incorrect order

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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);
  });
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading