Promise.all()在运行服务器时无法解析 - 否则运行正常

Ric*_*unn 9 javascript node.js promise

我写了一个小工具,在调用其他几个promises后返回一个promise.当我单独测试它时,这个工具很有用,在下面的例子中大约需要10秒.但是,当我尝试将它与http服务器实例一起运行时,如果有的话,需要几分钟才能返回!

我很确定我只是误解了一些东西,因为我不是非常精通Node.如果有人能够发现问题,或建议使用promises来替代处理异步方法,请告诉我们!

只是为了澄清,这是Promise.all通过返回的traceroute这是挂功能.子承诺都按预期解决.

编辑:正如评论中所建议的那样,我也尝试了一个没有调用Promise.all的递归版本; 同样的问题.

这是一个工作的独立版本,在没有运行任何http服务器实例的情况下调用:

const dns = require('dns');
const ping = require('net-ping');

var traceRoute = (host, ttl, interval, duration) => {

    var session = ping.createSession({
        ttl:ttl,
        timeout: 5000
    });

    var times = new Array(ttl);
    for (var i=0; i<ttl; i++){
        times[i] = {'ttl': null, 'ipv4': null, 'hostnames': [], 'times': []}
    };

    var feedCb = (error, target, ttl, sent, rcvd) => {
        var ms = rcvd - sent;
        if (error) {
            if (error instanceof ping.TimeExceededError) {
                times[ttl-1].ttl = ttl;
                times[ttl-1].ipv4 = error.source;
                times[ttl-1].times.push(ms)
            } else {
                console.log(target + ": " +
                error.toString () +
                " (ttl=" + ttl + " ms=" + ms +")");
            }
        } else {
            console.log(target + ": " +
            target + " (ttl=" + ttl + " ms=" + ms +")");
        }
    }

    var proms = new Array();
    var complete = 0

    while(complete < duration){
        proms.push(
            new Promise((res, rej) => {
                setTimeout(function(){
                    session.traceRoute(
                        host,
                        { maxHopTimeouts: 5 },
                        feedCb,
                        function(e,t){
                            console.log('traceroute done: resolving promise')
                            res();  // resolve inner promise
                        }
                    );
                }, complete);
            })
        )
        complete += interval;
    }

    return Promise.all(proms)
    .then(() => {
        console.log('resolving traceroute');
        return times.filter((t)=> t.ttl != null);
    });
}


traceRoute('195.146.144.8', 20, 500, 5000)
.then( (times) => console.log(times) )
Run Code Online (Sandbox Code Playgroud)

下面是从服务器实例内部调用的相同逻辑,这应该正常工作.请参阅内联注释,了解它的确切位置.

const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({server: server, path: "/wss"});
const dns = require('dns');
const ping = require('net-ping');

var traceRoute = (host, ttl, interval, duration) => {

    var session = ping.createSession({
        ttl:ttl,
        timeout: 5000
    });

    var times = new Array(ttl);
    for (var i=0; i<ttl; i++){
        times[i] = {'ttl': null, 'ipv4': null, 'hostnames': [], 'times': []}
    };

    var feedCb = (error, target, ttl, sent, rcvd) => {
        var ms = rcvd - sent;
        if (error) {
            if (error instanceof ping.TimeExceededError) {
                times[ttl-1].ttl = ttl;
                times[ttl-1].ipv4 = error.source;
                times[ttl-1].times.push(ms)
            } else {
                console.log(target + ": " + 
                error.toString () + " (ttl=" + ttl + " ms=" + ms +")");
            }
        } else {
            console.log(target + ": " + target + 
            " (ttl=" + ttl + " ms=" + ms +")");
        }
    }

    var proms = new Array();
    var complete = 0

    while(complete < duration){
        proms.push(
            new Promise((res, rej) => {
                setTimeout(function(){
                    session.traceRoute(
                        host,
                        { maxHopTimeouts: 5 },
                        feedCb,
                        function(e,t){
                            console.log('traceroute done: resolving promise')
                            res();  // resolve inner promise
                        }
                    );
                }, complete);
            })
        )
        complete += interval;
    }

    console.log('Promise all:', proms);

    // #####################
    // Hangs on this promise
    // i.e. console.log('resolving traceroute') is not called for several minutes.
    // #####################
    return Promise.all(proms)
    .then(() => {
        console.log('resolving traceroute')
        return times.filter((t)=> t.ttl != null)
    });
}

wss.on('connection', function connection(ws, req) {

    traceRoute('195.146.144.8', 20, 500, 5000)
    .then((data) => ws.send(data));

});

app.use('/tools/static', express.static('./public/static'));
app.use('/tools/templates', express.static('./public/templates'));

app.get('*', function (req, res) {
    res.sendFile(__dirname + '/public/templates/index.html');
});

server.listen(8081);
Run Code Online (Sandbox Code Playgroud)

注意:我试过在之前server.listen,之后server.listen,从内部调用它wss.on('connection', ....这些都没有区别.在服务器正在侦听时,在任何地方调用它会使其以不确定的方式运行.

Ric*_*unn 6

我不会接受这个答案,因为它只是一种解决方法; 放在评论中的时间太长了......

承诺,包括Promise.all,都没有抛出异常.但是,Node 似乎停止了对Promise.all的调用.我偶然发现,如果我在等待promise.all解析时保持超时循环运行,那么它实际上会在预期时解析.

如果有人能够解释到底发生了什么,我真的很喜欢,因为我不太懂.

var holdDoor = true
var ps = () => {
    setTimeout(function(){
        console.log('status:', proms);
        if (holdDoor) ps();
    }, 500);
}
ps();

return Promise.all(proms)
.then(() => {
    holdDoor = false
    console.log('Resolving all!')
    return times.filter((t)=> t.ttl != null)
});
Run Code Online (Sandbox Code Playgroud)