0

Problem:

I am trying to execute a series of functions in a specific order. These functions all have asynchronous tasks inside of them; however, these functions need to happen sequentially.

The below code needs to do the following:

  1. Delete current contents of Document Directory (this is because all files are persistent but I do NOT need them for permanent storage, only temporary)

  2. Copy current file assets from their locations to the Document Directory

  3. Zip up the folder of the Document Directory so I can store the zipped folder in AWS

Is it possible to ensure these functions wait for their asynchronous tasks to finish? (Some of these asynchronous tasks are run in a forEach loop -- this is not a single task within each function).

To take this a step further, can I execute the two (x2) copyFilesToDocumentDirectory() concurrently and still wait before executing zipDocumentDirectory()?

import React, { Component } from 'react';
import { zip } from 'react-native-zip-archive';
import RNFS from 'react-native-fs';

export default class AddMedia extends React.Component {
    
    state = { 
        photoAssets: [], 
        videoAssets: [], 
        videoThumbnails: [],
        thumbnailReady: false
    };

    zipDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        console.log("Zipped");
        zip(path, path + "/urls.zip")
        .then((path) => {
            console.log("Zip complete");
        })
        .catch((err) => {
            console.log(err);
        });
    };

    deleteContentsOfDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        var data = RNFS.readDir(path)
        .then((results) => {
            results.forEach(result => {
                /* I assume each item here is a FILE */
                RNFS.unlink(result.path)
                .then(() => {
                    console.log("File Deleted");
                })
                .catch((err) => {
                    console.log(err.message);
                });
            });
        });
    };

    copyFilesToDocumentDirectory(assets) {
        var path = RNFS.DocumentDirectoryPath;
        assets.forEach(asset => {
            RNFS.exists(asset.uri)
            .then((status) => {
                if(status) {
                    var newPath = path + "/" + asset.fileName;;
                    console.log("Copying from: ", asset.uri, " -- to: ", newPath);
                    RNFS.copyFile(asset.uri, newPath);
                };
            });
        });
    };
    
    storeToAWS() 
        this.deleteContentsOfDocumentDirectory();
        this.copyFilesToDocumentDirectory(this.state.photoAssets);
        this.copyFilesToDocumentDirectory(this.state.videoAssets);

        this.zipDocumentDirectory();
    
    };

    // ... Render code etc;
};

Efforts:

I wrote the above because that was the problem I am trying to solve. I thought this could be solved by Promises but I am relatively new to the idea of promises/async/await. I tried adding Promises to each method to wait for them to finish; however, the functions still ran synchronously and the asynchronous tasks ran after. The output is below the code showing the Zipped output inside zipDocumentDirectory() occurs BEFORE the asynchronous commands inside copyFilesToDocumentDirectory().

import React, { Component } from 'react';
import { zip } from 'react-native-zip-archive';
import RNFS from 'react-native-fs';

export default class AddMedia extends React.Component {
    
    state = { 
        photoAssets: [], 
        videoAssets: [], 
        videoThumbnails: [],
        thumbnailReady: false
    };

    zipDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        console.log("Zipped");
        new Promise((resolve, reject) => {
            zip(path, path + "/urls.zip")
            .then((path) => {
                console.log("Zip complete");
                resolve();
            })
            .catch((err) => {
                console.log(err);
                reject();
            });
        });
    };

    deleteContentsOfDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        new Promise((resolve, reject) => {
            var data = RNFS.readDir(path)
            .then((results) => {
                results.forEach(result => {
                    /* I assume each item here is a FILE */
                    RNFS.unlink(result.path)
                    .then(() => {
                        console.log("File Deleted");
                        resolve();
                    })
                    .catch((err) => {
                        console.log(err.message);
                        reject();
                    });
                });
            });
        });
    };

    copyFilesToDocumentDirectory(assets) {
        var path = RNFS.DocumentDirectoryPath;
        assets.forEach(asset => {
            new Promise((resolve, reject) => {
                RNFS.exists(asset.uri)
                .then((status) => {
                    if(status) {
                        var newPath = path + "/" + asset.fileName;;
                        console.log("Copying from: ", asset.uri, " -- to: ", newPath);
                        RNFS.copyFile(asset.uri, newPath);
                        resolve();
                    };
                });
            });
        });
    };
    
    storeToAWS = async () => {
        await this.deleteContentsOfDocumentDirectory();
        await this.copyFilesToDocumentDirectory(this.state.photoAssets);
        await this.copyFilesToDocumentDirectory(this.state.videoAssets);

        // 2. Zip temporary folder storage (with encryption)
        await this.zipDocumentDirectory();
OUTPUT:

 LOG  Zipped
 LOG  Copying from:  XYZ/FEB964FB-3ABB-4CF7-A3B0-1E90BD1932C4.jpg  -- to:  XYZ/FEB964FB-3ABB-4CF7-A3B0-1E90BD1932C4.jpg
5
  • You wrapped your functions with new promises but you never used resolve. The most important part is that you have to return the promise from the function, not only create it Commented Oct 17, 2022 at 21:51
  • @KonradLinkowski I added them (As well as edited the question) and it still runs synchronously without waiting for the asynchronous tasks to finish. Commented Oct 17, 2022 at 21:55
  • @KonradLinkowski You said return the promise from the function -- I see; I didn't do that here. How would I return multiple promises? i.e. my functions wrap these promises in a forEach iteration since I have to do it to each. If I were to return, only the first promise would return, no? Commented Oct 17, 2022 at 22:00
  • Change forEach to map and use Promise.all. You don't need to create a new promise when you already have a promise exposed like RNFS.exists(asset.uri) Commented Oct 17, 2022 at 22:05
  • Ahhhhh. I can just return the RNFS.exists -- I seeeee. Neat-o. Feel free to put it as an Answer and I'll make sure it all works out and give it the Good ole Green Check Commented Oct 17, 2022 at 22:10

1 Answer 1

1

I added missing returns. I hope it will work now

import React, { Component } from 'react';
import { zip } from 'react-native-zip-archive';
import RNFS from 'react-native-fs';

export default class AddMedia extends React.Component {
    
    state = { 
        photoAssets: [], 
        videoAssets: [], 
        videoThumbnails: [],
        thumbnailReady: false
    };

    zipDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        console.log("Zipped");
        return zip(path, path + "/urls.zip")
        .then((path) => {
            console.log("Zip complete");
        })
        .catch((err) => {
            console.log(err);
            reject();
        });
    };

    deleteContentsOfDocumentDirectory() {
        var path = RNFS.DocumentDirectoryPath;
        return RNFS.readDir(path)
        .then((results) => {
            return Promise.all(results.map(result => {
                return RNFS.unlink(result.path)
                .then(() => {
                    console.log("File Deleted");
                })
                .catch((err) => {
                     console.log(err.message);
                });
            }));
        });
    };

    copyFilesToDocumentDirectory(assets) {
        var path = RNFS.DocumentDirectoryPath;
        return Promise.all(assets.map(asset => {
            return RNFS.exists(asset.uri)
                .then((status) => {
                    if(status) {
                        var newPath = path + "/" + asset.fileName;;
                        return RNFS.copyFile(asset.uri, newPath);
                    };
                });
            });
        }));
    };
    
    storeToAWS = async () => {
        await this.deleteContentsOfDocumentDirectory();
        await this.copyFilesToDocumentDirectory(this.state.photoAssets);
        await this.copyFilesToDocumentDirectory(this.state.videoAssets);

        // 2. Zip temporary folder storage (with encryption)
        await this.zipDocumentDirectory();
    }
}
    ```
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.