从for循环中返回一个promise

时间:2014-09-01 11:48:12

标签: javascript foreach promise winjs

我有一个递归函数,我试图让它按顺序运行,每次都返回promise。 代码是递归的并且运行良好,但仅适用于for循环中的第一项。

示例:

  • 文件夹:1 - 确定
  • 文件夹:11 - 确定
  • 文件夹:111 - 确定
  • 文件夹:111 - 确定
  • 文件夹:2 - 不行
  • 文件夹:12 - 不行
  • 所有异步下载按顺序完成。

我认为这是因为当我从内部返回promise时,for循环就会被中断。

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.");
})

知道如何在不中断for循环的情况下返回promise吗?

PS:如果我使用forEach厕所它不会被打断,但是我失去了按顺序返回文件夹的能力。

示例:

  • 文件夹:1 - 确定
  • 所有异步下载按顺序完成。
  • 文件夹:11 - 确定
  • 文件夹:111 - 确定
  • 文件夹:111 - 确定
  • 文件夹:2 - 确定
  • 文件夹:12 - 确定

1 个答案:

答案 0 :(得分:4)

是的,就像使用任何函数一样,如果执行return语句,该函数将停止它正在执行和返回的内容。您应该能够完成以下所做的事情:

编辑:如果您不需要按特定顺序完成这些操作,则可以使用WinJS.Promise.join()(又名Promise.all()完成您要执行的操作在其他承诺方言)和map(我在这里分解内部部分以减少嵌套):

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);
           });
}

作为完整的附注,请不要将for...in与数组一起使用。这是一个坏主意。

作为这篇文章的一个遗迹,如果你需要,你可以按顺序创建文件夹(虽然不建议这样做):

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;
}

如图here所示,做同样事情的另一种稍微清洁的方法是使用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());
    });
}