Promise.all()解析,但不应该(node.js)

时间:2016-01-17 18:23:36

标签: javascript node.js asynchronous promise

我现在正在node.js中尝试这样的事情:

var exec = require('child_process').exec
var write = require('fs-writefile-promise')

function run() {
    var myArray = [];   
    var execs = [];

    for (var i = 1; i <= 7; i++) {
        (function(cntr) {
            write('file-' + i + '.txt', someString)
            .then(function (filename) {
                execs.push(new Promise(function(resolve, reject) {
                    exec('cat ' + 'file-' + cntr + '.cnf', function(error, stdout, stderr) {
                        console.log(cntr + ' ' + stdout);
                        if (stdout.search(/\bsomeString\b/) > -1) {
                            myArray.push(cntr);
                            resolve();
                        } 
                        else {
                            resolve();
                        }   
                    })
                }))
            })
            .catch(function (err) {
                console.error(err);
            });
        })(i);
    }
    return Promise.all(execs).then(function() {
        return new Promise(function(resolve) {
            resolve(myArray);
        }) 
    })
}

run().then(function(result) {
    console.log(result);
});

正如您所看到的,我正在创建多个运行exec()的Promise,并且每个Promise在exec()完成时解析。 然后我等待每个Promise在Promise.all(execs)中解决以返回myArray作为承诺。然而,当我在最后执行我的run()函数时,它返回一个空数组。我想这与Promise.all()有关,因为即使execs中的某些Promise尚未解决,它也会解决,但我不确定,这就是为什么我真的需要一些帮助。有谁知道我在代码中犯了什么错误?

非常感谢你!

#EDIT 1

var exec = require('child_process').exec
var write = require('fs-writefile-promise')

function run() {
    var myArray = [];   
    var execs = [];

    for (var i = 1; i <= 7; i++) {
        (function(cntr) {
            return new Promise(function(resolve, reject) {
                fs.writeFile('file-' + i + '.txt', someString, (err) => {
                    if (err) {
                        reject();
                    }
                    else {
                        resolve();
                    }
                });
            })
            .then(function (filename) {
                execs.push(new Promise(function(resolve, reject) {
                    exec('cat ' + 'file-' + cntr + '.cnf', function(error, stdout, stderr) {
                        console.log(cntr + ' ' + stdout);
                        if (stdout.search(/\bsomeString\b/) > -1) {
                            myArray.push(cntr);
                            resolve();
                        } 
                        else {
                            resolve();
                        }   
                    })
                }))
            })
            .catch(function (err) {
                console.error(err);
            });
        })(i);
    }
    return Promise.all(execs).then(function() {
        return new Promise(function(resolve) {
            resolve(myArray);
        }) 
    })
}

run().then(function(result) {
    console.log(result);
});

2 个答案:

答案 0 :(得分:2)

您的尝试都有很多问题。第一次尝试的问题是你在异步操作之后填充了execs数组,所以当你实际将数组传递给Promise.all()时它没有任何内容,因此Promise.all()没有什么可以等待的。

此外,您不仅仅使用已经创建的承诺,因此您最终会获得比所需更多的承诺。

一般情况下,最好在主逻辑之外“实现”异步操作,然后让所有逻辑成为承诺驱动,而不是将承诺与普通回调混合和匹配。这是一个试图解决这些问题的版本:

var exec = require('child_process').exec
var write = require('fs-writefile-promise')

// make promisified version of exec
function execP(file, options) {
    return new Promise(function(resolve, reject) {
        exec(file, options, function(err, stdout, stderr) {
            if (err) return resolve(err);
            resolve({stdout: stdout, stderr: stderr});
        });
    });
}

function run() {
    var promises = [];
    for (var i = 1; i <= 7; i++) {
        promises.push(write('file-' + i + '.txt', someString).then(function(filename) {
            return execP(filename);
        }));
    }
    return Promise.all(promises).then(function(results) {
        // results is an array of {stdout: xxx, stderr: yyy} objects
        // process those results into a new array of just indexes
        var final = [];
        results.forEach(function(data, index) {
            if (data.stdout.search(/\bsomeString\b/) > -1) {
                final.push(index);
            }
        });
        return final;
    });
}

run().then(function(results) {
    // array of indexes that contained the desired search string
}, function(err) {
    // process error here
});

注意:这会并行运行您的所有exec操作,这是您的原始代码所做的操作。如果你想按顺序运行它们,也可以这样做,但需要进行一些调整。

答案 1 :(得分:1)

由于write是异步的,所以此阶段的程序将返回主线程,直接进入你的promise.all并在加载execs之前返回。

我建议你创建一个函数,它返回的承诺文件保存后跟exec。