Home > other >  Async / await problem, The Async / await function is returning true before the value is placed in th
Async / await problem, The Async / await function is returning true before the value is placed in th

Time:02-19

I am creating a multiple image file upload using firebase and react-typescript. My main problem is with async/await. I have a function called uploadFiles which will save the downloaded URLs into my URLs state. But the problem is uploadFiles returning true while the URLs are still loading to set into the state.

My expectation is until setUrls state new values are placed into the setUrls state the Async / await will not return true.

I have explained in the video also, https://youtu.be/t6JqasRCPRM

Live code: https://codesandbox.io/s/eloquent-pine-tdv3wf?file=/src/AddProduct.tsx:2777-2941

The main problem is here: setURLs are taking time to set into the state.

  async () => {
    await getDownloadURL(uploadTask.snapshot.ref).then((downloadURLs: any) => {
         setURLs((prevState: any) => [...prevState, downloadURLs])
         console.log("2 File available at", downloadURLs);
});

Also, another problem is that promise is returning true while the URLs are still loading to set into the state.

   try {
            await Promise.all(promises);
            setSuccess(true);
            return true;
        } catch (e) {
            console.error(e);
            return false;
        }

UploadFiles function:

 const uploadFiles = async (files: any) => {

        const promises: any = []
        files.map((file: any) => {

            const sotrageRef = ref(storage, `files/${file.name}`);
            const uploadTask = uploadBytesResumable(sotrageRef, file);
            promises.push(uploadTask)
            uploadTask.on(
                "state_changed",
                (snapshot: any) => {
                    const prog = Math.round(
                        (snapshot.bytesTransferred / snapshot.totalBytes) * 100
                    );
                    setProgress(prog);
                },
                (error: any) => console.log(error),
                async () => {
                    await getDownloadURL(uploadTask.snapshot.ref).then((downloadURLs: any) => {
                        setURLs((prevState: any) => [...prevState, downloadURLs])
                        console.log("2 File available at", downloadURLs);

                    });
                }
            );


        })

        try {
            await Promise.all(promises);
            setSuccess(true);
            return true;
        } catch (e) {
            console.error(e);
            return false;
        }
    };

uploadWasSuccessful is returning true I want until the setURls is available my if statement will not go to the next step.

  const handleProductSubmit = async (e: any) => {
        e.preventDefault()

        const uploadWasSuccessful: any = await uploadFiles(images) // returning true but the urls are still loading.
        console.log('uploadWasSuccessful', uploadWasSuccessful);
        console.log('Success', success);

        if (uploadWasSuccessful) {
            const newProductValue = { ...productValue, URLs }
            console.log(newProductValue, 'productValue');
        }

    }

CodePudding user response:

The setSuccess(true) call here is not asynchronous. This means its running immediately before the promises are resolved. Add await here to wait for the promises to resolve above.

try {
            await Promise.all(promises);
            await setSuccess(true); //await
            return true;
        } catch (e) {
            console.error(e);
            return false;
        }

also make the uploads promises by including await here:

 const sotrageRef = ref(storage, `files/${file.name}`);
            const uploadTask = await uploadBytesResumable(sotrageRef, file); //added await
            await promises.push(uploadTask) //added await

CodePudding user response:

The trick I normally use is that the uploadTask it itself a promise already, so you can await it or chain its then, and just skip the approach with (at least) the third callback:

const uploadFiles = async (files: any) => {

  const promises: any = []
  files.map((file: any) => {
    const storageRef = ref(storage, `files/${file.name}`);
    const uploadTask = uploadBytesResumable(storageRef, file);
    const urlTask = uploadTask.then(() => storageRef.getDownloadURL); //            
  • Related