BlowFish
BlowFish

Reputation: 354

Function gets trigger before promise is resolved

I have this two functions, writedb is supposed to act only when uploadImages is done. I'm not getting what I'm hoping for. The resolve shows "null" for "this.imageURL" as is predefined but is triggered before the console.log that are inside the loop which show the correct wanted information.

      uploadImages() {
            return new Promise(async (resolve, reject) => {
                let newImageURL = []
                for (const path of this.images){
                        fs.readFile(path,
                            async (err, data) => {  
                                const ref = st.ref(`images/${this.id}/${path.split('/').pop()}`);
                                await ref.put(data);
                                let url = await ref.getDownloadURL();
                                
                                newImageURL.push(url);
                                this.imageURL = newImageURL; 
                                console.log(this.imageURL);
                        })
                }
                resolve(console.log(this.name),
                        console.log(this.imageURL),
                        console.log('Done upload images'))
            }) 
        }
    
        writedb(){
            (() => {
                let obj = {};
                this.uploadImages().then(
                    console.log('writedb in action...'),
                    db.collection("products").doc(this.id).set(Object.assign(obj, this))
                )
            })();
        }

What am I doing wrong here? How can i get the promise to resolve only if the for loop is done??

Upvotes: 1

Views: 365

Answers (2)

BlowFish
BlowFish

Reputation: 354

With CertainPerformance help I've corrected my code as follows

Thank you! After some though I finally was able to implement it and achieve the expected result.

uploadImages (){
        return Promise.all(this.imagespath.map(
            path => fs.promises.readFile(path)
            .then(async (data)=>{
                const ref = st.ref(`images/${this.id}/${path.split('/').pop()}`);
                await ref.put(data);
                return ref.getDownloadURL();
            })
        ))
    }

    writedb(){
        this.uploadImages()
        .then((res)=>{
            this.imageURL = res;
            
            //Firebase no toma custom objects Object.assign(obj, this)
            let obj ={} 
            Object.assign(obj, this);
            delete obj.imagespath;

            db.collection("products").doc(this.id).set(obj) 
            
        }).catch( err=>console.log(err) )
    }

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370679

Use fs.promises and Promise.all to wait for each readFile to resolve - and avoid the explicit Promise construction antipattern:

uploadImages() {
    return Promise.all(this.images.map(
        path => fs.promises.readFile(async (data) => {
            const ref = st.ref(`images/${this.id}/${path.split('/').pop()}`);
            await ref.put(data);
            return ref.getDownloadURL();
        })
    ));
}

Then instance.uploadImages() will return a Promise that resolves to an array of the data you want. uploadImages().then((result) => { /* do stuff with result */ }).catch(handleErrors);

Upvotes: 2

Related Questions