javascript Node.js + Socket.io 超出最大调用堆栈大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27376522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 07:24:46  来源:igfitidea点击:

Node.js + Socket.io Maximum call stack size exceeded

javascriptnode.jssocket.io

提问by noden00b

For my Node application, I have a server (app.js) running on Debian serving both html and websocket data using socket.io to my client (index.html). I am attempting to make a turn-based HTML5 multiplayer game.

对于我的 Node 应用程序,我有一个在 Debian 上运行的服务器 (app.js),它使用 socket.io 向我的客户端 (index.html) 提供 html 和 websocket 数据。我正在尝试制作一个回合制 HTML5 多人游戏。

After performing a number of successful data transmissions using socket.emit()/io.emit() and socket.on(), my server crashes on an socket.emit() call with the error
"events.js:72
throw er; //Unhandled 'error' event
RangeError: Maximum call stack size exceeded".
I have quite a few socket.on() event listeners, with each one handling a different function in the game (e.g. roll_dice, end_turn, ready_to_play, etc.).

使用 socket.emit()/io.emit() 和 socket.on() 执行了多次成功的数据传输后,我的服务器在 socket.emit() 调用时崩溃,错误为
“events.js:72
throw er; //未处理的'错误'事件范围错误
:超出最大调用堆栈大小”。
我有很多 socket.on() 事件侦听器,每个侦听器在游戏中处理不同的功能(例如 roll_dice、end_turn、ready_to_play 等)。

I attempted researching the problem (found a lot of discussion on async loops), but was unable to find how to apply the solutions to my own code. I attached relevant source here. You can also view all the source on my github at: https://github.com/sjmoon0/gameofdeath

我试图研究这个问题(发现了很多关于异步循环的讨论),但无法找到如何将解决方案应用于我自己的代码。我在这里附上了相关的来源。您也可以在我的 github 上查看所有源代码:https: //github.com/sjmoon0/gameofdeath

index.html

索引.html

var socket = io.connect('http://131.178.15.173',{'forceNew':true});
 
                    ...

  //----------------Initialization and Menu functions-----------
  socket.on('load', function (data) {
    console.log(data);
    clientID=data;
    socket.emit('check_game_started', { un: clientID });
    socket.on('last_client_loaded', function(hasStarted){
     console.log("Has game started? :"+hasStarted);
     if(hasStarted==true){
      $('#choosecharacter').show();
     }
    });
  });

  socket.on('client_disconnect', function (data) {
    console.log(data);
  });

  socket.on('client_counter', function (data) {
    if(data<5){
     console.log(data);
     incrementLoadBar(data); 
     allowedInGame=true;
    }
    if(!allowedInGame){
     ...
    }
  });

  socket.on('game_started', function (data) {
    console.log(data);
    $('#welcome').hide();
    $('#choosecharacter').show();
  });

  socket.on('set_user', function(characterName){
   chosenCharacter=characterName;
  });

  socket.on('disable_player_choice', function(data){
   var id=data.stuff[0].chara;
   incrementLoadBar(data.stuff[0].numChar);
   console.log(id +" was chosen");
   $('#'+id).hide();
  });


//-------------------Gameplay functions
  socket.on('start_gameplay',function(nonsense){
   showChanges(nonsense);
 $('#wait').hide();
 $('#gamespace').show();
 draw_c();
 socket.emit('ready_to_play',chosenCharacter);
  });

  socket.on('take_turn',function(updatedBoard){
   showChanges(updatedBoard);
   if(updatedBoard.currPlayer==chosenCharacter){
    promptUser(updatedBoard);
   }
  });

  socket.on('roll_result',function(rollResult){
   promptUser(rollResult);
  });

                  ...
                  

 $('#rollDiceButton').click(function(){
  socket.emit('roll_dice',chosenCharacter);
 });

 $('#okCloseButton').click(function(){
  socket.emit('end_turn',chosenCharacter);
 });

 $('.thumbnail').click(function(something){
  socket.emit('player_chosen', something.target.id);
              ...
 });

app.js

应用程序.js

var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
var url = require('url');

...

app.listen(8001);

function handler (req, res) {
...
}
console.log("~Server Running~");


io.on('connection', function (socket) {
  console.log("A Client connected");
  ...
  socket.emit('load', { user: uID });
  io.emit('client_counter',numClients);

  if(numClients==4){
      gameStarted=true;
      console.log("Game started!");
      io.emit('game_started',"The Game has begun!");
    }
    else if(numClients>4){
      numClients--;
      delete allClients[allClients.indexOf(socket)];
    }

  socket.on('check_game_started', function (data) {
    socket.emit('last_client_loaded', gameStarted);
    console.log(data);
    if(gameStarted){
      console.log("Last Player Loaded!");
    }
  });

  socket.on('player_chosen', function(cp){
    ...
    socket.emit('set_user', cp);
    ...
    io.emit('disable_player_choice',{'stuff':[{'chara':cp,'numChar':numCharChosen}]});
    if(numCharChosen==4){
      io.emit('start_gameplay', boardUpdate);
    }
  });

  socket.on('disconnect',function(){
    console.log("A client disconnected");
    numClients--;
    delete allClients[allClients.indexOf(socket)];
    io.emit('client_disconnect',"We've lost another comrade!");
  });

  socket.on('ready_to_play',function(characterThatIsReadyToPlay){
    io.emit('take_turn',boardUpdate);
  });

  socket.on('roll_dice', function(characterThatRolledDice){
    var temp=generateRollResult(characterThatRolledDice)
    socket.emit('roll_result',temp);
  });

  socket.on('end_turn',function(characterThatEndedTurn){
    io.emit('take_turn',nextUpdate(characterThatEndedTurn));
  });
});

Please be gentle, I just started using Node.js about a week ago. Thanks!

请温柔一点,我大约一周前才开始使用 Node.js。谢谢!

回答by noden00b

Found my issue.

发现我的问题。

The object (temp) I was trying to send over the network (in socket.emit('roll_result',temp);) was a self-referencing array. It was the recursive property of the array that caused the stack to exceed the max size.

我试图通过网络发送的对象 (temp)(在 socket.emit('roll_result',temp); 中)是一个自引用数组。正是数组的递归属性导致堆栈超过最大大小。

回答by Fan Gong

The answer is very helpful. Thanks.

答案非常有帮助。谢谢。

I just had the same issue and want to share with anyone who might encounter it.

我刚刚遇到了同样的问题,想与可能遇到它的任何人分享。

My code uses express.js and has the following:

我的代码使用 express.js 并具有以下内容:

io = require('socket.io').listen(server);
......
io.to(socketId).emit('hello', {userId:userId, data:data, res:res});

It generated the "Maximum call stack exceeded" error. The problem is that I should not send the variable 'res' over the socketio to the client. I guess it will cause some recursive behavior if I do so.

它生成了“超出最大调用堆栈”错误。问题是我不应该通过 socketio 将变量“res”发送到客户端。我想如果我这样做会导致一些递归行为。

The solution is just remove the 'res' from the emit statement:

解决方案只是从emit语句中删除“res”:

io.to(socketId).emit('hello', {userId:userId, data:data});

回答by Mangesh Sathe

This is the same error I came across, When I clicked on submit button. It was getting disabled and throwing "Maximum call stack size exceeded". I restarted my browser, It worked.. Strange behaviour

这与我遇到的错误相同,当我点击提交按钮时。它被禁用并抛出“超出最大调用堆栈大小”。我重新启动了浏览器,它起作用了.. 奇怪的行为

回答by firatto

I would like to share my mistake on the same issue:

我想在同一个问题上分享我的错误:

    public createClient() {
    this.client = new net.Socket();
    this.client.connect(this.port, this.ip, () => {
        this.emit("connect");
    });

    this.client.on("data", (data) => {
        this.emit("data", data);
    });

    this.client.on("close",function () => {
        this.emit("close");
    });

}

in close event, using normal function and this ( cause of error ) cause a loop of close event emit and the result is stack size error .

在关闭事件中,使用普通函数和 this(错误原因)导致关闭事件发出循环,结果是堆栈大小错误。

    this.client.on("close", () => {
        this.emit("close");
    });

Using arrow func. ( or copying real this into something like _this and using inside function ) solved issue.

使用箭头函数。(或将真实的 this 复制到 _this 之类的东西并使用内部函数)解决了问题。

This is actually being ignorant about function context ( in callback ), or negligence ..

这实际上是对函数上下文(在回调中)一无所知,或者疏忽..

回答by Erez Fishhimer

I had the same issue. For me the problem was that the object I was emitting on the socket held a reference to the socket itself. So I was basically sending a socket inside a socket. Don't try this at home :)

我遇到过同样的问题。对我来说,问题是我在套接字上发出的对象持有对套接字本身的引用。所以我基本上是在一个套接字内发送一个套接字。不要在家里尝试这个:)

回答by Amera Abdallah

I had the same problem, it happened because I was sending 3 objects with the emit I solved it by sending only one object

我遇到了同样的问题,这是因为我发送了 3 个带有发射的对象,我只发送了一个对象就解决了这个问题

回答by McWally

I had the same issue too, but in my case it's a bit funny because I actually was emitting the error event socket.on("error", new Error(err))in my catchblock. It was fixed with just changing the emitted event because erroris a private event. LOL

我也有同样的问题,但就我而言,这有点有趣,因为我实际上是socket.on("error", new Error(err))在我的catch块中发出错误事件。由于error是私人事件,因此只需更改发出的事件即可修复。哈哈