【问题标题】:node.js call stack exceeded with sockets.iosockets.io 超出了 node.js 调用堆栈
【发布时间】:2018-08-05 19:03:07
【问题描述】:

我正在做一个项目,我必须不断轮询网络(本地网络)上许多设备的状态,然后通过 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

【问题讨论】:

  • 是不是因为递归使用了test函数?
  • 我怀疑是这样,但如果它在错误处理中没有调用 io.sockets.emit() 函数的情况下运行,那么它运行几个小时都没有问题。只要我在if(err) 中添加该调用,它就会崩溃......
  • 这取决于你压入堆栈的程度,不是吗?您可以发布一些内容以便重现您的问题吗?还是你的代码就够了?
  • 不得不改变 "setTimeout(()=>{io.sockets.emit("error", err)},50);"让它运行。
  • 这在我的机器上似乎没有奏效。超出调用堆栈大小时出现相同的错误。它可能是 socket.io 模块中的东西吗?我没有附加任何客户端来接收 socket.io 消息,但我会以某种方式期望在任何其他情况下也会发生此错误......

标签: node.js socket.io callstack


【解决方案1】:

我刚刚想通了。

This 的帖子有同样的错误,修复也适用于此。

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

将此更改为非自引用对象使其即使没有setTimeout()也可以工作

【讨论】:

  • 谢谢。但我必须了解自引用对象是什么。
猜你喜欢
  • 2016-12-04
  • 2014-01-23
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2016-09-26
  • 1970-01-01
  • 2014-12-03
相关资源
最近更新 更多