0

I want to have a loading screen where the current state is displayed while resources are loading in the background. Therefore I use an async function. I don't know much about async in JavaScript but in C# and I want to use it the same way so I just call the function.

Here is the relevant code:

// main.js
async function loadAssets() {
    var loadingInfo = document.getElementById("loading-info");
    loadingInfo.innerHTML = "Loading entity data..."
    entityDB = JSON.parse(FileReader.read("https://my-domain.com/data/entity-db.json"));
    loadingInfo.innerHTML = "Done...";
}

// file_reader.js
class FileReader {
    static read(fileName) {
        try {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", fileName, false);
            xmlhttp.send();

            if (xmlhttp.status == 200)
                return xmlhttp.responseText;

            return null;
        } catch (error) {
            return null;
        }
    }
}

The problem is that I never see the loading text. The UI freezes for 4 seconds and then the text Done is displayed. Am I misunderstanding async in JavaScript?

Kaskorian
  • 426
  • 3
  • 18
  • 1
    [FileReader is a built-in class](https://developer.mozilla.org/en-US/docs/Web/API/FileReader); giving your class the same name is going to confuse maintainers (probably including the you of 6 months in the future). – Quentin Apr 19 '21 at 06:17

2 Answers2

2

The async keyword has two effects:

  • It makes the function return a promise
  • It allows you to use the await keyword inside it to cause it to go to sleep while it waits for a promise to resolve

It doesn't make blocking code run asynchronously.

You have no asynchronous code. Normally XMLHttpRequest does run asynchronously but you passed false as the third argument to open() triggering the deprecated synchronous mode.


If you want to make an HTTP request asynchronously and deal with the results using promises then you can:

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
1

You should use fetch that can be awaited and extract JSON data. Also forcing an asynchronous operation to become synchronous is always a bad idea. You should embrace asynchronism and learn how to work with it, instead of freezing your code execution.

class FileReader {
    static async read(fileName) {
        try {
            const response = await fetch(fileName);
            const data = await response.json();
            return data
        } catch (error) {
            return null;
        }
    }
}


async function loadAssets() {
    const loadingInfo = document.getElementById("loading-info");
    loadingInfo.innerHTML = "Loading entity data..."
    const entityDB = await FileReader.read("https://my-domain.com/data/entity-db.json");
    loadingInfo.innerHTML = "Done...";
}
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • "It should be new FileREader().read(...)" — No, it is implemented with the `static` keyword so it is a property of the class, not of instances. – Quentin Apr 19 '21 at 06:16
  • 1
    Ha thanks, I actually never knew what `static` was. That's very useful to know. I'll edit my answer accordingly – Jeremy Thille Apr 19 '21 at 06:17
  • @Quentin Edited, do you think the code is better now? – Jeremy Thille Apr 19 '21 at 06:20
  • Yes (in so far as it can be made better while keeping the OP's use of a static method as a simple wrapper function). – Quentin Apr 19 '21 at 06:23
  • Oh yes, keeping OP's structure. I wouldn't use a Class just to wrap a `fetch` call either, a simple helper function would do. – Jeremy Thille Apr 19 '21 at 06:26