递归函数内的异步调用

4

我正在使用CEF用Javascript构建本地桌面应用程序,并且我有API来从CEF访问文件系统。 我有一个场景,需要获取特定目录中所有文件的名称(可能存在目录树)。 我需要获得结果数组,我正在使用jQuery promises。 我不明白的是:何时解决承诺以获得最终结果数组?

/*read all directories under this and get path*/
    var result = [];
    function _processEntries(dirPath) {
        var dirEntry = new NativeFileSystem.DirectoryEntry(dirPath), deferred = new $.Deferred();

        /*async call*/
        dirEntry.createReader().readEntries(
            function (entries) {
                for (var i = 0; i < entries.length; i++) {
                    if (entries[i].isDirectory) {
                        _processEntries(entries[i].fullPath).done(function () {
                            deferred.resolve(result);
                        });
                    } else {
                        result.push(entries[i].fullPath);
                    }
                }
            },
            function (error) {
                console.log("Failed while reading dir:", error);
            }
        );
        return deferred.promise();
    }

// 调用函数

_processEntries("C:/Users/abc").done(function(result){
    console.log("FILES ARRAY:",result);
});
如果我做得不对,请建议其他技术:)

尽可能不要使用jQuery promises,当你可以轻松地使用更好的promise库时。 - Bergi
2个回答

0

嗯,我看到了一些错误。当第一个子目录返回时,您解决了整个承诺,但必须等待所有子目录完成各自的承诺,而且您正在解决全局变量而不是内部变量。请查看以下示例并进行更改:

function _processEntries(dirPath) {
    var result = [];
    var dirEntry = new NativeFileSystem.DirectoryEntry(dirPath), deferred = new $.Deferred();

    /*async call*/
    dirEntry.createReader().readEntries(
        function (entries) {
            var promises = [];
            for (var i = 0; i < entries.length; i++) {
                if (entries[i].isDirectory) {
                    promises.push(_processEntries(entries[i].fullPath));
                } else {
                    result.push(entries[i].fullPath);
                }
            }

            if(promises.length === 0) {
              deferred.resolve(result);
            } else {
               $.when.apply($,promises).done(function() {
                result.concat(arguments);
                deferred.resolve(result);
              })
            }
        },
        function (error) {
            console.log("Failed while reading dir:", error);
        }
    );
    return deferred.promise();
}

0
什么时候解决这个 Promise? 在异步调用结束后立即解决它。否则你会遇到 deferred antipattern 的问题。避免这个问题,你可以在任何地方使用 Promise,并与它们进行适当的组合。 此外,你不应该在 _processEntries 函数之外初始化你的 result 变量——你会在多次调用函数时遇到严重的问题。
function getDirectoryEntries(dirPath) {
    // a promise helper function
    var dirEntry = new NativeFileSystem.DirectoryEntry(dirPath),
        deferred = new $.Deferred();
    dirEntry.createReader().readEntries(deferred.resolve, deferred.reject);
    return deferred.promise();
}
function _processEntries(dirPath) {
    return getDirectoryEntries(dirPath).then(function (entries) {
        var promises = [];
        for (var i = 0; i < entries.length; i++) {
             if (entries[i].isDirectory) {
                  promises.push(_processEntries(entries[i].fullPath));
             } else {
                  promises.push($.when(entries[i].fullPath));
             }
        }
        return $.when.apply($, promises).then(function() {
             return [].concat.apply([], arguments);
        });
    });
}

这样调用:

_processEntries("C:/Users/abc").then(function(result){
    console.log("FILES ARRAY:",result);
}, function (error) {
    console.log("Failed while reading dir:", error);
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,