Search code examples
javascriptreact-nativeasynchronouspromisexmlhttprequest

Promise is skipping XMLHttpRequest


I'm trying to do XMLHttpRequest with Promise.all like this way

        Promise.all(image.map(imageUpload => {              
            let xhr = new XMLHttpRequest()
            xhr.open('POST', MY_REQUEST_URL)
            xhr.onload = () => {
              alert('imageUpload.name')
            }
            xhr.onerror = (err) => {
               alert('error')
            }
            let formdata = new FormData();
            formdata.append('file', {uri: imageUpload.path, type: 'image/png', name: 'image.png'});
            xhr.send(formdata)
        })).then(async s => {
               alert('done')
        })

but the problem is Promise.all is not waiting until the xhr request finish, it just sends a request and alert, thats it!

any ideas?


Solution

  • Your callback to .map doesn't return anything - but it needs to return a Promise to work with Promise.all

    Promise.all(image.map(imageUpload => new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open('POST', MY_REQUEST_URL);
        xhr.addEventListener('load', resolve);
        xhr.addEventListener('error', reject);
    
        // if you must alert in a loop of XHR's add these
        // I've made this code separate because I think it's a terrible idea™
        xhr.addEventListener('load', () => alert('imageUpload.name'));
        xhr.addEventListener('error', () => alert('error'));
    
        let formdata = new FormData();
        formdata.append('file', {uri: imageUpload.path, type: 'image/png', name: 'image.png'});
        xhr.send(formdata);
    }))).then(async s => {
        alert('done')
    });
    

    however, modern technique is to use fetch which is already a Promise based native API

    Promise.all(image.map(imageUpload => {
        let formdata = new FormData();
        formdata.append('file', {uri: imageUpload.path, type: 'image/png', name: 'image.png'});
        return fetch(MY_REQUEST_URL, {
            method: "POST",
            body: formdata
        })
        // probably don't need this line, since you don't actually care about the response
        .then(response => response.text())
        // and if you must alert during a loop of asynchronous code ...
        // though I think it's a terrible idea™
        .then(() => alert('imageUpload.name'))
        .catch(err => {
            alert('error');
            throw err; // without this, the rest of the code thinks you've succeeded when you've failed
        });
    })).then(async s => {
        alert('done');
    })