Skip to content
Advertisement

XMLHttpRequest return from a function before response is back

I have a function as the code below, I am trying to send a file through XMLHttpRequest to the server and then store it in DB and retrieve the id of the file in DB and make an object of ids. The problem is that the function exits a lot before I got the response back from the server to store it in the object therefore the object doesn’t store those values. I know that I need make the XHR asynchronous but it doesn’t change the result, I have also tried timeout or using a different platform like Ajax but still, it didn’t work.

async function getFileObj() {
    var FileObject = {}
    for (let key1 in PObj) {
        FileObject[key1] = {}
        for (let key2 in PObj[key1]) {
            FileObject[key1][key2] = {}
            for (let key3 in PObj[key1][key2]) {
                const formData = new FormData();
                formData.append('myFile.png', filesObjDB[key1][key2][key3]);

                var xhr = new XMLHttpRequest();
                xhr.open("POST", 'url', true);
                xhr.onreadystatechange = async function() {
                    if (this.readyState === XMLHttpRequest.DONE && this.status === 200)
                        var id = await xhr.response.text();
                        FileObject[key1][key2][key3] = parseInt(id)
                }
                xhr.responseType = 'blob';
                xhr.send(formData);
            }
        }
    }
    return FileObject;
}

Help would be very appreciated!

Advertisement

Answer

You are not awaiting the request. To make the existing code wait for the result, you’d need to wrap the outdated callback-based code in a promise and await that (and also I don’t think getting the response text of an XHR works as you showed, I changed it now):

// This is just to demonstrate what was immediately wrong
// with the existing code - it's not the best solution! See below. 

FileObject[key1][key2][key3] = await new Promise((resolve, reject) => {
  var xhr = new XMLHttpRequest();
  xhr.open("POST", url, true);
  xhr.onreadystatechange = function() {
    if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
      var id = xhr.responseText;
      resolve(parseInt(id));
    }
  };
  xhr.send(formData);
});

Note there is no error handling yet, if the request fails everything will just hang.

But at that point, it doesn’t actually make sense to use XHR in the first place! It’s a lot more straightforward to use fetch, which has a promise API out of the box:

const response = await fetch(url, { method: 'POST', body: formData })
FileObject[key1][key2][key3] = parseInt(await response.text())
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement