承诺失灵

时间:2017-02-15 16:08:54

标签: javascript node.js express promise

我有一个承诺嵌套在另一个看起来像这样的承诺:

 adb.screencap(list, id).then(function(missing) {
     adb.getScreens(list, id).then(function () {
         res.render('screencap', {output: "Screens captured."})
     })
 })

adb.screencap和adb.getScreens是:

adb.screencap = function(list, id){
    return new Promise(function (resolve, reject) {
        var array = new Array();
        var promises = new Array();

        for (var i = 0; i < list.length; i++) {
            var cmd = "adb -s " + list[i] + " shell screencap /sdcard/" + list[i] + "-" + id + ".png";
            var missing = new Array();

            console.log("== " + cmd);
            promises.push(adb.openArray(i, array, list, cmd, missing));
        }
        Promise.all(promises).then(function (missing) {
            console.log(("resolve"));
            resolve(missing);
        })
    })
}
adb.getScreens = function(list, id){
    return new Promise(function (resolve, reject){
        for (var i = 0; i < list.length; i++) {
            var cmd = 'adb -s ' + list[i] + ' pull /sdcard/' + list[i] + "-" + id + ".png /home/IdeaProjects/DeviceServer/public/files/" + list[i] + "-" + id + ".png";
            exec(cmd, function (err, stdout, stderr) {
                console.log(stdout);
                console.log(cmd);
            });
        }
        resolve();
    })
}

在adb.screencap承诺之前,adb.getScreens承诺是否有任何理由完成?

3 个答案:

答案 0 :(得分:1)

我仍在试图弄清楚出了什么问题,因为这似乎很奇怪。 它可能位于openArray()方法或exec()函数中。

对于它的价值,你可以简化一些事情,正如菲利克斯建议的那样:

// If the getScreens handler doesn't need the 'missing' returned from screencap
adb.screencap(list, id).then(function(missing) {
    return adb.getScreens(list, id);
}).then(function ( gottenScreens ) {
    res.render('screencap', {output: "Screens captured."})
});

// You can just return the Promise.all here instead of adding another promise
// just to resolve the outer one.
adb.screencap = function(list, id) {
    var array = new Array();
    var promises = new Array();
    for (var i = 0; i < list.length; i++) {
        var cmd = "adb -s " + list[i] + " shell screencap /sdcard/" + list[i] + "-" + id + ".png";
        var missing = new Array();

        console.log("== " + cmd);
        // is this some async operation or are you just creating all the commands here?
        // if so, it does't make sense to use a promise here.
        promises.push(adb.openArray(i, array, list, cmd, missing));
    }       
    return Promise.all(promises);
}

答案 1 :(得分:1)

您正在解决getScreens()内部任何exec()次来电之前的问题。他们是异步的。他们稍后会完成,但是在你启动它们之后,你就会立即致电resolve()。因此,在您需要渲染的任何结果可用之前,您最终会尝试渲染。

相反,您需要宣传exec()本身,然后在数组中收集这些承诺,并使用Promise.all()查看所有这些承诺何时完成。只有这样才能getScreens()实际完成。

这里还有很多其他问题。 screencap()正在使用反模式。这里没有必要创建自己的承诺。您可以从Promise.all()返回承诺,并且使用此反模式会导致您丢失任何承诺所引发的任何错误。

这是一个建议:

// promisify exec
function execP(cmd) {
    return new Promise(function(resolve, reject) {
        exec(cmd, function(err, stdout, stderr) {
            if (err) return reject(err);
            console.log(cmd);
            console.log(stdout);
            console.log(stderr);
            resolve({stdout: stdout, stderr: stderr});
        });
    });
}

adb.getScreens = function(list, id){
    return Promise.all(list.map(function(item) {
       var cmd = 'adb -s ' + item + ' pull /sdcard/' + item + "-" + id + ".png /home/IdeaProjects/DeviceServer/public/files/" + item + "-" + id + ".png";
       return execP(cmd);
    }));
}

现在.getScreens()会返回一个只有在完成所有exec()调用后才会解决的承诺(这样您的输出文件就可以使用并为您的redner做好准备)。

这会将.getScreens()配置为解析为包含所有exec调用中的stdout,stderr信息的对象数组。无论如何,您似乎没有尝试使用该输出,但这是如何配置的。

答案 2 :(得分:0)

您的module.exports = { context: path.resolve(__dirname, 'src'), entry: { main: './main.js' }, output: { path: path.resolve(__dirname, './dist'), publicPath: "/dist", filename: '[name].js' }, module: { rules: [ //... { test: /\.(jpg|jpeg|png|svg)$/, use: [{ loader: 'file-loader?name=[name].[ext]&outputPath=/images/' }] }, //... ] } }; 是否会回复承诺?然后只有adb.openArray才有效。

如果Promise.all,你应该在回调中解决getScreens的承诺。它在外面,不等待exec完成。