迭代数组并等待承诺 [英] Iterate array and wait for promises

查看:63
本文介绍了迭代数组并等待承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 Promise 遍历数据数组并返回数据?我已经看到了一些 promises.push(asyncFunc) 方法,但是我的数组中的一些条目会失败,所以从我收集的信息来看,我不能使用它.

How can I iterate through an array of data using Promises and returning data? I have seen some promises.push(asyncFunc) methods but some of the entries from my array will fail so from what I gather I can't use that.

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) 这就是为什么我想要在那里返回数据.

I start start(dbFiles) from another file which is why I want the data returned there.

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 链有效,所有数据都在上面的 for 循环中返回 (getMp4(dbFiles[i]))

So for every entry in my array I want to check if the file with the new extension exists and read that file. If the file with extension does not exist I fulfill the original file. My Promise.all chain works and all the data is returned in for loop above (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);
            }
        });
    });
};

getMp4 中 Promise.all 链中的方法 - 我知道这些方法没有问题.

Methods in the Promise.all chain in getMp4 - have no problems with these that I know.

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

推荐答案

如果你需要它们并行运行,Promise.all 就是你想要的:

If you need them to run in parallel, Promise.all is what you want:

function start(dbFiles) {
    return Promise.all(dbFiles.map(getMp4));
}

这会为所有文件启动 getMp4 操作并等待它们全部完成,然后使用结果数组进行解析.(getMp4 将接收多个参数 — 值、它的索引和对 dbFiles 数组的引用  但因为它只使用第一个,所以很好.)

That starts the getMp4 operation for all of the files and waits until they all complete, then resolves with an array of the results. (getMp4 will receive multiple arguments — the value, its index, and a a reference to the dbFiles arary — but since it only uses the first, that's fine.)

用法:

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([]));
}

同样的用法.请注意我们如何从一个用 [] 解析的 promise 开始,然后将一堆 then 处理程序排队,每个处理程序接收数组,执行 getMp4调用,得到结果后将结果压入数组并返回;最终的分辨率值是填充的数组.

Same usage. Note how we start with a promise resolved with [], then queue up a bunch of then handlers, each of which receives the array, does the getMp4 call, and when it gets the result pushes the result on the array and returns it; the final resolution value is the filled array.

这篇关于迭代数组并等待承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆