Home > Mobile >  Array length not updated after async / await function
Array length not updated after async / await function

Time:09-04

So i'm fetching images from a remote server. then converting these images to base64 and pushing them to an empty array. the problem is the array length outside of that function doesn't get updated. i'm pretty sure it has to do something with the async/await function.

here's my code

const handleSubmit = async (listing) => { 

    const product = {files:[]};
            const getBase64StringFromDataURL = (dataURL) => dataURL.replace('data:','').replace(/^. ,/, '');
    
            for (let image of listing.images) {
                    await fetch(image)
                        .then((res) => res.blob())
                        .then((blob) => {
                            // Read the Blob as DataURL using the FileReader API
                            const reader = new FileReader();
                            reader.onloadend = () => {
                                const base64 =  getBase64StringFromDataURL(reader.result);
                                product.files.push(base64)
                                // here the product.files length is updated without a problem                                
                               console.log(product.files.length)
                            };
                            reader.readAsDataURL(blob);
                        });
               } 
        // here the length is 0 
        console.log(product.files.length)

}

please help figure this out. i'm open to a better alternative !

CodePudding user response:

fileReader.onload is asynchronous, I think console.log() is called before files have been read. You might want to make use of promise.all & map like this -

Promise.all([...listing.images].map(image => fetch(image)))
.then(resp => Promise.all(resp.map(file => new Promise((resolve, reject) => {
    var blob = await file.blob();
    var fileReader = new FileReader();
    fileReader.onloadend = function readFile(e) {
        const base64 =  getBase64StringFromDataURL(reader.result);
        resolve(base64);
    };
    reader.readAsDataURL(blob)
}))
.then(result => {
    // get result array here
});

Use a promise & map instead of for loop.

CodePudding user response:

if you are using await, you don't need then. instead you get result directly.
reader.onloadend is asynchronous. so I suggest writing a wrapper function for it:

async function pushToArray(inputBlob, inputArray) {

 return new Promise((resolve, reject)=>{
  const reader = new FileReader();
  reader.onloadend = () => {

    /*logic...*/
    inputArray.push(base64);
    resolve();   // resolve should be here

  };
  reader.readAsDataURL(inputBlob);
  

 });
}

// now your code be like:
let res = await fetch(image);
let blob = await res.blob();  // if res.blob() return a promise
await pushToArray(blob, product.files);


console.log(product.files.length); // 1



  • Related