return a promise from inside a for loop

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-24 19:14:42

问题


I have a recursive function and I am trying to make it run in sequence, returning the promise every time. The code is recursive and works well but works only for the first item in the for loop.

Example:

  • folder: 1 - OK
  • folder: 11 - OK
  • folder: 111 - OK
  • folder: 111 - OK
  • folder: 2 - NOT OK
  • folder: 12 - NOT OK
  • All asynchronous downloads completed in sequence.

I think it is because when I return the promise from inside, then the for loop gets interrupted.

function CopySubFolders(folder, destFolder) {

    // Recursively copy each subfolder
    return folder.getFoldersAsync()
    .then(function (folderlist) {
        if (folderlist.size > 0) {
            for (var i in folderlist) {
                var replace = Windows.Storage.CreationCollisionOption.replaceExisting;
                console.log("create folder: " + folderlist[i].name);

                return destFolder.createFolderAsync(folderlist[i].name, replace)
                .then(function (newdest) {
                   return CopySubFolders(folderlist[i], newdest);
                });
            }
        }
        else {
            return WinJS.Promise.as();
        }
    });
}


CopySubFolders(folder, self.localFolder)
.then(function () {
    completeFunc("Done");
    console.log("All asynchronous downloads completed in sequence.");
})

Any idea how to return the promise without interrupting the for loop?

PS: if I use a forEach loo it will not get interrupted, but then I loose the capability of returning the folders in sequence.

Example:

  • folder: 1 - OK
  • All asynchronous downloads completed in sequence.
  • folder: 11 - OK
  • folder: 111 - OK
  • folder: 111 - OK
  • folder: 2 - OK
  • folder: 12 - OK

回答1:


Yes, just like with any function, if you execute a return statement, the function will stop what it's doing and return. You should be able to accomplish what you're trying to do with the following:

Edit: if you don't need them to complete in a specific sequence, you can accomplish what you are trying to do with WinJS.Promise.join() (a.k.a. Promise.all() in other promise dialects) and map (I'm factoring out the inner part here to cut down on the nesting):

function CopySubFolders(folder, destFolder) {
    return folder.getFoldersAsync()
    .then(function (folderlist) {
        return WinJS.Promise.join(folderlist.map(function (folder) {
            return CopyFolder(folder, destFolder);
        });
    });
}

function CopyFolder(folder, destFolder) {
    var replace = Windows.Storage.CreationCollisionOption.replaceExisting;
    console.log("create folder: " + folder.name);

    return destFolder.createFolderAsync(folder.name, replace)
           .then(function (newdest) {
                return CopySubFolders(folder, newdest);
           });
}

As a complete side note, please don't use for...in with arrays. It's a bad idea.

And as a bit of a vestige of this post, here is how you would be able to create the folders in sequence if you needed to (though that is not recommended):

function CopySubFolders(folder, destFolder) {
    var p = Promise.resolve();

    return folder.getFoldersAsync()
    .then(function (folderlist) {
        return folderlist.forEach(function (folder) {
            var replace = Windows.Storage.CreationCollisionOption.replaceExisting;
            console.log("create folder: " + folder.name);

            p = p.then(function () {    
                destFolder.createFolderAsync(folder.name, replace)
                .then(function (newdest) {
                    return CopySubFolders(folder, newdest);
                });
            });
        });
    });

    return p;
}

Another slightly cleaner way to do the same thing, as illustrated here, is to use folderlist.reduce():

function CopySubFolders(folder, destFolder) {
    return folder.getFoldersAsync()
    .then(function (folderlist) {
        return folderlist.reduce(function (sequence, folder) {
            var replace = Windows.Storage.CreationCollisionOption.replaceExisting;
            console.log("create folder: " + folder.name);

            return sequence.then(function () {    
                destFolder.createFolderAsync(folder.name, replace)
                .then(function (newdest) {
                    return CopySubFolders(folder, newdest);
                });
            });
        }, Promise.resolve());
    });
}


来源:https://stackoverflow.com/questions/25605215/return-a-promise-from-inside-a-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!