迭代数组并等待承诺

3

如何使用Promises迭代数据数组并返回数据?我看到过一些promises.push(asyncFunc)的方法,但我的一些数组条目将失败,所以我不能使用它。

var filesFromDisk = [
    '41679_4_2015-09-06_17-02-12.mp4',
    '41679_4_2015-09-06_17-02-12.smil',
    '41680_4_2015-09-09_10-44-05.mp4'
];

start(filesFromDisk)
    .then((data) => {
        console.log(data); // Want my data here
});

我从另一个文件开始运行 start(dbFiles),因此我希望数据返回到那里。

function start(dbFiles) {
    var listOfFiles = [],
        promises = [];
    return new Promise((fulfill, reject) => {
        for (var i = 0; i < dbFiles.length; i++) { 
            getMp4(dbFiles[i])
                .then((data) => {
                    listOfFiles = listOfFiles.concat(data);
                    console.log(listOfFiles);
                })
        }
        fulfill(listOfFiles) // Need to happen AFTER for loop has filled listOfFiles
    });
}

因此,对于数组中的每个条目,我想要检查新扩展名的文件是否存在并读取该文件。如果不存在具有扩展名的文件,则使用原始文件。我的Promise.all链有效,并且所有数据在上面的循环中(getMp4(dbFiles[i]))返回。

function getMp4(filename) {
    var mp4Files = [];
    var smil = privateMethods.setSmileExt(localData.devPath + filename.toString());
    return new Promise((fulfill, reject) => {
        Promise.all([
            privateMethods.fileExists(smil),
            privateMethods.readTest(smil)
        ]).then(() => {
            readFile(filename).then((files) => {
                fulfill(files)
            });
        }).catch((err) => {
            if (!err.exists) fulfill([filename]);
        });
    });
}

function readFile(filename){
    var filesFromSmil = [];
    return new Promise((fulfill, reject) => {
        fs.readFile(localData.devPath + filename, function (err, res){
            if (err) {
                reject(err);
            }
            else {
                xmlParser(res.toString(),  {trim: true}, (err, result) => {
                    var entry = JSON.parse(JSON.stringify(result.smil.body[0].switch[0].video));
                    for (var i = 0; i < entry.length; i++) { 
                        filesFromSmil.push(privateMethods.getFileName(entry[i].$.src))
                    }
                });
                fulfill(filesFromSmil);
            }
        });
    });
};

Promise.all 链中 getMp4 方法没有我所知道的任何问题。

var privateMethods = {
    getFileName: (str) => {
        var rx = /[a-zA-Z-1\--9-_]*.mp4/g;
        var file = rx.exec(str);   
        return file[0];
    },
    setSmileExt: (videoFile) => {
        return videoFile.split('.').shift() + '.smil';
    },
    fileExists: (file) => {
        return new Promise((fulfill, reject) => {
            try {
                fs.accessSync(file);
                fulfill({exists: true})
            } catch (ex) {
                reject({exists: false})
            }
        })
    },
    readTest: (file) => {
        return new Promise((fulfill, reject) => {
            fs.readFile(file, (err, res) => {
                if (err) reject(err);
                else fulfill(res.toString());
            })
        })
    }
}

1
你需要让它们并行运行还是顺序运行? - T.J. Crowder
只要我的起始点中的数据在.then()中是完整的,它们就可以并行运行。如果我理解你的意思正确。 - Thomas Johansen
1个回答

7
如果您需要并行运行它们,Promise.all 就是您想要的:
function start(dbFiles) {
    return Promise.all(dbFiles.map(getMp4));
}

这会启动getMp4操作,对所有文件进行处理并等待所有操作完成,然后返回结果数组。(getMp4将接收多个参数——值、其索引和对dbFiles数组的引用——但由于它只使用第一个参数,所以这很好。)

用法:

start(filesFromDisk).then(function(results) {
    // `results` is an array of the results, in order
});

为了完整起见,如果需要按顺序运行它们,可以使用“reduce”模式:
function start(dbFiles) {
    return dbFiles.reduce(function(p, file) {
        return p.then(function(results) {
            return getMp4(file).then(function(data) {
                results.push(data);
                return results;
            });
        });
    }, Promise.resolve([]));
}

同样的用法。请注意,我们从一个已解决的承诺[]开始,然后排队一堆then处理程序,每个处理程序接收数组,进行getMp4调用,当它获得结果时将结果推送到数组中并返回它;最终解析值是填充的数组。


@Alnitak: 天哪,我真的写了 .map(function(file) { return getMp4(file); })!需要更多的咖啡。谢谢。(已修复。) - T.J. Crowder
不客气 :) 多余的函数封装总是让我很困扰... :p - Alnitak
1
@ThomasJohansenToft:如果getMp4解析了承诺并返回,那么该解析值将在数组中。恐怕我无法帮助您调试getMp4中发生的情况,但以上绝对是如何并行执行一堆操作并获得所有操作结果的最终结果的方法。 - T.J. Crowder
1
@danrichardson - 不用担心!如果你真的想按顺序完成任务,那么这样做没有任何问题。 - T.J. Crowder
1
@danrichardson - 别担心!不,这样做没有问题,如果你真的想按顺序完成事情的话。 - undefined
显示剩余4条评论

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