4

我是新的承诺。我正在尝试 ping 一些机器以检查它们是否处于活动状态。我正在使用本机 NodeJS 承诺。我的ping功能:

function ping(addr) {
    return new Promise(function(resolve, reject) {
        var args = ['-n', '1', '-w', '5000'];
        args.push(addr);
        var ls = cp.spawn('ping.exe', args);

        ls.on('error', function (e) {
            reject(Error('There was an error while executing the ping'));

        });

        ls.on('exit', function (code) {
            if(code === 0) {
                resolve({host: addr});
            } 
            else {
                reject(Error(addr + " is  down!"));
            }

        });
    });

}

现在,我有从 JSON 读取的数组中机器的详细信息:

gulp.task('pingNodes', ['readConfigJSON'], function () {

    var batches = ConfigJSON.NodeDetails.Batch1.concat(ConfigJSON.NodeDetails.Batch2);
    var pingPromises = batches.map(function (host) {
        return ping(host.Name)
            .then(function (res) {
                console.log(res.host + " is  up!");
            }).catch(function (err) {
                console.log(err);
            });
    });
    return Promise.all(pingPromises).then(function(){console.log("All nodes are up!")});
});

现在即使某个节点关闭,它也不会拒绝:

[16:58:46] Starting 'init'...
Starting Deployment
[16:58:46] Finished 'init' after 135 µs
[16:58:46] Starting 'readConfigJSON'...
[16:58:46] Finished 'readConfigJSON' after 204 µs
[16:58:46] Starting 'pingNodes'...
machine1 is  up!
machine2 is  up!
machine3 is  up!
[Error: machine4 is  down!]
All nodes are up!
[16:58:49] Finished 'pingNodes' after 2.54 s
4

1 回答 1

5

解决方案

要解决此问题,请在处理程序中再次抛出错误catch,如下所示

}).catch(function (err) {
    console.log(err);
    throw err;
});

或删除catch处理程序。基本上,您应该让拒绝沿着链条向下流动,以便Promise.all在机器停机时获得拒绝的承诺。


基本理解

  1. 所有的thencatch处理程序都会创建一个新的 Promise 对象并返回它们,以便我们可以将它们链接起来。

  2. 当一个 Promise 被拒绝时,一个拒绝处理程序会处理它,但如果拒绝处理程序没有拒绝该承诺,那么链中的后续处理程序将不会将该承诺视为已拒绝。

在您的情况下,当机器停机时,您正在拒绝它并且拒绝处理,

}).catch(function (err) {
    console.log(err);
});

但是,catch处理程序返回一个未被拒绝的承诺。所以,Promise.all实际上得到了一个未被拒绝的 Promise 对象。这就是为什么它不会在发现其中一台机器停机时立即停止。

您可以通过以下程序确认这种理解

var a = Promise.resolve(1)
    .then(function (e) {
        throw e;
    })
    .catch(function (e) {
        // This is what you are doing if the machine is down
        console.log(e);

        // No rejection here, so `then` will be called.
        // Uncomment the throw to see 
        // throw e;
    });

a.then(function (e) {
    console.log("Inside then")
});

a.catch(function (e) {
    console.log("Inside catch")
});

于 2015-06-10T11:49:22.380 回答