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

时间:2014-12-09 10:20:26

标签: 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
扔掉; //未处理的'错误'事件
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);
		            ...
	});

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));
  });
});

请保持温和,我刚开始使用Node.js一周前。谢谢!

9 个答案:

答案 0 :(得分:41)

找到我的问题。

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

答案 1 :(得分:6)

答案非常有用。感谢。

我遇到了同样的问题,并希望与可能遇到此问题的任何人分享。

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

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

它生成了#34;超出最大调用堆栈&#34;错误。问题是我不应该发送变量&#39; res&#39;通过对客户的保护。我想如果我这样做会导致一些递归行为。

解决方案就是删除&#39; res&#39;来自emit语句:

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

答案 2 :(得分:0)

这是我遇到的同一个错误,当我点击提交按钮时。它被禁用并投掷&#34;超出最大调用堆栈大小&#34;。我重启了我的浏览器,它工作..奇怪的行为

答案 3 :(得分:0)

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

    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");
    });

}

在关闭事件中,使用正常功能,并且此(错误原因)会导致发出关闭事件循环,结果是堆栈大小错误。

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

使用箭头功能。 (或将真实的内容复制到_this这样的内容中并使用内部函数)解决了问题。

这实际上是对函数上下文(在回调中)或疏忽大意的无知。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我遇到了同样的问题,这是因为我发送了3个对象,而我只通过发送一个对象解决了这个问题

答案 6 :(得分:0)

我也遇到同样的问题,但就我而言,这有点可笑,因为我实际上是在socket.on("error", new Error(err))块中发出了错误事件catch。由于error是私有事件,因此仅通过更改发出的事件即可解决。哈哈

答案 7 :(得分:0)

就我而言,我不小心通过 socket.io 发送了 Promise

答案 8 :(得分:-1)

我在使用 Socket.io、express server 和 p5.js 库制作实时白板应用程序时遇到了同样的问题。 我试图使用套接字将 p5 向量发送到导致错误的服务器。

这是我的代码 txtPos = createVector(mouseX / width, mouseY / height); let data = { pos: txtPos, txt: "", h: colorSlider.value(), b: brighSlider.value(), size: sizeSlider.value(), }; texts.push(data); socket.emit("newText", data);

^ 上面的代码抛出一个错误,因为我想发送的数据对象包含 txtPos(p5 vector),其中包含 p5 对象,其中包含 p5 向量,而 p5 向量又包含 p5 对象,并且它会一直持续下去。 ..就像一个递归对象(圆形对象)。

为了解决这个问题,我的新代码非常简单。

我换了

pos:txtPos,

pos:{ x:txtPos.x, y:txtPos.y, } 猜猜现在我能够成功发送这些数据了。 :D