node.js 超出调用堆栈 sockets.io

node.js call stack exceeded with sockets.io

我正在做一个项目,我必须不断轮询网络(本地网络)上许多设备的状态,然后通过 socket.io 连接将其状态发送给客户端。

当与设备的连接良好时,我可以获取代码并运行,但如果其中一个设备掉线,我会得到:

RangeError: Maximum call stack size exceeded 
    at Function.isBuffer (buffer.js:398:36)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:42:87)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)
    at hasBinary (c:\Projects\Active\AL10-2.0\al10-server_sqlite\node_modules\has-binary2\index.js:56:59)

我的代码如下所示:

var express = require("express");
var app = express();
var http = require("http").Server(app);
var Client = require("node-rest-client").Client;
var rest = new Client();
var io = require("socket.io")(http);
var sqlite3 = require("sqlite3");

function test(counter=0, list=[]){
    // console.log(counter);
    if(list.length == 0 || counter >= list.length){
        var query = "SELECT url FROM paths";
        db.all(query, (err,data) => {
            if(err){
                throw (err);
            }
            test(0, data);
        });
    }
    else{
        setTimeout( () => {
            GetStatus(list[counter].url, (err, restData) => {
                if(err){
                    /* As soon as one of these are added, 
                    the callstack is exceeded */
                    // setTimeout(io.sockets.emit("error", err),50);
                    // io.sockets.emit("error", err);
                    console.log(err);
                }
                else{
                    /* This one is no problem */
                    io.sockets.emit("status", restData);
                    console.log(counter + " - " + restData.HeartBeat);
                }
                // process.nextTick(test, ++counter, list);
                test(++counter, list);
            });
        },1000);
    }
}

function GetStatus(url, callback){
    var req = rest.get(url, ((data,response) => {
        if(response.statusCode == 200){
            callback(null,data);
        }
        else{
            callback(response.statusCode,null);
        }
    }).bind(this));

    req.on("error",(function(err){
        /* All of the following yeilds the same result */
        callback(err,null);
        // process.nextTick(callback,err,null);
        // setTimeout(callback(err,null),0);
    }).bind(this));
}


var db = new sqlite3.Database(":memory:", (err) => {
    if(err) return;
});

db.serialize(() => {
    var values = ["http://192.168.42.69/restapi/status","http://192.168.42.70/restapi/status"];
    db.run("CREATE TABLE paths(url text)")
    .run("INSERT INTO paths(url) VALUES (?),(?)", values, (err) => {
        if(err){
            throw err;
        }
        test();
    });
});

当我添加 io.sockets.emit("error",err);(有或没有 setTimeout(...))时,代码失败并给出 RangeError。

以上代码是一个孤立的测试,试图找出它不起作用的原因。在实际的应用程序中,还有更多的 url,它们可能会随着时间的推移而改变。在实际应用中,这个例程还会时不时查询数据库中url的变化...

我试图实现 this post 中的一些答案,但无济于事。

所以我的问题是,为什么 socket.io 调用会导致堆栈溢出? 还有,我该如何让它发挥作用?

我正在使用

node.js - 8.9.4
socket.io - 2.0.3
sqlite3 - 3.1.13
node-rest-client - 3.1.0
express - 4.15.3

我刚刚弄明白了。

This post 有同样的错误,这里的修复也有效。

问题是 GetStatus(list[counter].url, (err, restData) => {...}) 中剩余调用的 err 对象。按原样发送时,err 对象是 self-referencing 并导致调用堆栈被淹没。

将其更改为 non-self 引用对象使其即使没有 setTimeout()

也能正常工作