How to assemble the JavaScript async fetch results in the "original order"

Viewed 58

The good thing about async is, it speeds up the fetch, and we get whatever is available first instead of server to respond.

But this messes up the ORDER of the requests which in this case is important for me.

I wanted to scrape different parts of a continuous story, so the order is a must.

Here's what I did:

async function getSingle(url) {
    await fetch(url).then(function (response) { 
        return response.text();
    }).then(function (html) {    
        var output = document.querySelector('.output');
        output.innerHTML=html;          
        text += "\n" + document.querySelector('.post-body').innerText;
    });
}

It gets everything perfectly, but when I call it for multiple URLs, it returns them unordered.

[Beginner here, so please pardon if it's something really trivial.]

2 Answers

You function the same with (I recommended use async/await completely)

async function getSingle(url) {
  const response = await fetch(url);
  const html = await response.text();

  const output = document.querySelector('.output');
  output.innerHTML = html;
  text += "\n" + document.querySelector('.post-body').innerText; // "text" ???
}

To keep the order, you can call the function in order by a for-loop, the request will be called one by one:

const urls = ['url1', 'url2'];

for (const url of urls) {
  await getSingle(url);
}

If you want to call the requests in parallel, let's use Promise.all. But you have to refactor your function - it will returns html string:

async function getSingle(url) {
  const response = await fetch(url);
  const html = await response.text();
  return html
}

const htmls = await Promise.all(urls.map(url => getSingle(url));
for (const html of htmls) {
  const output = document.querySelector('.output');
  output.innerHTML = html;
  text += "\n" + document.querySelector('.post-body').innerText; // "text" ???
}

You could try to keep track of the order they were sent, then when you receive the response, try and add your html to them dom in the same order. something like this (I didn't test it):

let order = [];
let index = 0;
let completed_index=0;

async function getSingle(url) {
    let i=index++;
    order[i] = {index:i}
    await fetch(url).then(function (response) { 
        order[i] = response.text();
    }).then(function (html) {
    while(order[completed_index]!==undefined{
        completed_index++;
        var output = document.querySelector('.output');
        output.innerHTML=order[completed_index];          
        text += "\n" + document.querySelector('.post-body').innerText;
        }
    });
}

you might want to clear the array afterwards

Related