0

I'm trying to do the following:

  • Function that returns a promise that checks if a directory exists (it creates is if it doesn't)

  • Then copy a file to that created directory.

The way I'm doing it, the copy the file part gets executed before the promise itself! So it fails because there is no directory there yet!

Code: IMG_DIR_ENTRY is a global variable inside the controller.

addImage

function addImage(imageURI) {
        return $q(function (resolve, reject) {

            handleImgDirCreation().then(function(imageDirEntry) {
                window.resolveLocalFileSystemURL(imageURI, function onResolveImgSuccess(imgFileEntry) {
                    imgFileEntry.copyTo(imageDirEntry, "img_" + + new Date(), function onCopySuccess(copiedImgFileEntry) {
                        images.push(copiedImgFileEntry.toURL());
                        window.localStorage.setItem(IMAGE_STORAGE_KEY, JSON.stringify(images));
                        resolve();
                    },
                    function onCopyFail(errMsgCopy) {
                        console.debug("ERROR: copy failed because: " + errMsgCopy);
                        reject();
                    });
                },
                function onResolveImgFail(errMsgResolveImg) {
                    console.debug("ERROR: couldn't resolve img because: " + errMsgResolveImg);
                    reject();
                });
            });
        });
    }


handleImgDirCreation (this is not getting called before the .then())

function handleImgDirCreation() {
        return $q(function(resolve, reject) {

            window.resolveLocalFileSystemURL(IMAGE_DIR, function onDirExists(imageDirEntry) {
                console.debug("SUCCESS: Directorio images ya existe.");
                resolve(imageDirEntry);
            },
            function onNonExistent(errMsgNonExistent) {
                createImageDirectory("WARNING: Directory didn't exist... || " + errMsgNonExistent);
                resolve(IMG_DIR_ENTRY);
            });
        });
    }


createImageDirectory

function createImageDirectory(errMsg) {
        console.debug(errMsg);
        console.debug("Creating IMG DIR --> " + IMAGE_DIR);

        window.resolveLocalFileSystemURL(DATA_DIRECTORY, function onResolveRootSuccess(rootDirEntry) {
            rootDirEntry.getDirectory('images', {create : true}, function onCreateDirSuccess(imgDirEntry) {
                console.debug("SUCCESS: Directory created --> " + imgDirEntry.toURL());
                IMG_DIR_ENTRY = imgDirEntry;
            },
            function onCreateDirFail(errMsgCreateDir) {
                console.debug("ERROR: Couldn't create image directory because: " + errMsgCreateDir);
            });
        },
        function onResolveRootFail(errMsgResolveRoot) {
            console.log("ERROR: Couldn't resolve root directory because: " + errMsgResolveRoot);
        });

    }

IMPORTANT I'm doing it with async promises because otherwise Android's main thread (UI Thread) gets overloaded and blocked and skips frames. Maybe there is another approach that I do not know of.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Franch
  • 621
  • 4
  • 9
  • 22

1 Answers1

1

To have code wait for the directory to be created, the createImageDirectory function needs to return a promise:

function createImageDirectory(errMsg) {
    var future = $q.defer();
    console.debug(errMsg);
    console.debug("Creating IMG DIR --> " + IMAGE_DIR);

    window.resolveLocalFileSystemURL(DATA_DIRECTORY, function onResolveRootSuccess(rootDirEntry) {
        rootDirEntry.getDirectory('images', {create : true}, function onCreateDirSuccess(imgDirEntry) {
            console.debug("SUCCESS: Directory created --> " + imgDirEntry.toURL());
            IMG_DIR_ENTRY = imgDirEntry;
            //RESOLVE with imgDirEntry;
            future.resolve(imgDirEntry);
        },
        function onCreateDirFail(errMsgCreateDir) {
            console.debug("ERROR: Couldn't create image directory because: " + errMsgCreateDir);
            //REJECT with error
            future.reject(errMsgCreateDir);
        });
    },
    function onResolveRootFail(errMsgResolveRoot) {
        console.log("ERROR: Couldn't resolve root directory because: " + errMsgResolveRoot);
        //REJECT with error
        future.reject(errMsgResolveRoot);
    });
    //RETURN promise
    return future.promise;

}

Then the handleImgDirCreation function needs to resolve with that promise:

function handleImgDirCreation() {
    return $q(function(resolve, reject) {

        window.resolveLocalFileSystemURL(IMAGE_DIR, function onDirExists(imageDirEntry) {
            console.debug("SUCCESS: Directorio images ya existe.");
            resolve(imageDirEntry);
        },
        function onNonExistent(errMsgNonExistent) {
            //createImageDirectory("WARNING: Directory didn't exist... || " + errMsgNonExistent);
            //resolve(IMG_DIR_ENTRY);
            var msg = "WARNING: Directory didn't exist... || " + errMsgNonExistent
            var directoryPromise = createImageDirectory(msg)
            //RESOLVE with directory promise
            resolve(directoryPromise);
        });
    });
}

By resolving with a directory creation promise, subsequent methods chained from that promise will wait for the creation of the directory.

Since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.

— AngularJS $q Service API Reference (Chaining Promises)

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95