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

nod*_*00b 11 javascript node.js socket.io

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

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

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

的index.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);
		            ...
	});
Run Code Online (Sandbox Code Playgroud)

app.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));
  });
});
Run Code Online (Sandbox Code Playgroud)

请温柔,我刚开始使用Node.js一周前.谢谢!

nod*_*00b 45

找到了我的问题.

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


小智 6

答案非常有帮助.谢谢.

我刚遇到同样的问题,想与可能遇到它的人分享.

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

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

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

解决方案是从emit语句中删除'res':

io.to(socketId).emit('hello', {userId:userId, data:data});
Run Code Online (Sandbox Code Playgroud)


小智 5

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