Socket.io: RangeError: se excedió el tamaño máximo de la pila de llamadas

Creado en 4 jul. 2014  ·  32Comentarios  ·  Fuente: socketio/socket.io

Solo estoy llamando `ìo.sockets.emit ('hey', data); and it will crash with RangeError: El tamaño máximo de la pila de llamadas excedió . I use it in other places in my app and it works fine. I am not repeating this (checked with console). The logs say the error is in socket.io/node_modules/has-binary-data/index.js: 46 ''.

No sé dónde está el problema. Intenté registrar io.sockets justo antes de usarlo y muestra esto:

{ name: '/',
17:39:37 web.1  |   server:
17:39:37 web.1  |    { nsps: { '/': [Circular] },
17:39:37 web.1  |      _path: '/socket.io',
17:39:37 web.1  |      _serveClient: true,
17:39:37 web.1  |      _adapter: [Function: Adapter],
17:39:37 web.1  |      _origins: '*:*',
17:39:37 web.1  |      sockets: [Circular],
17:39:37 web.1  |      eio:
17:39:37 web.1  |       { clients: [Object],
17:39:37 web.1  |         clientsCount: 2,
17:39:37 web.1  |         pingTimeout: 60000,
17:39:37 web.1  |         pingInterval: 25000,
17:39:37 web.1  |         upgradeTimeout: 10000,
17:39:37 web.1  |         maxHttpBufferSize: 100000000,
17:39:37 web.1  |         transports: [Object],
17:39:37 web.1  |         allowUpgrades: true,
17:39:37 web.1  |         allowRequest: [Function],
17:39:37 web.1  |         cookie: 'io',
17:39:37 web.1  |         ws: [Object],
17:39:37 web.1  |         _events: [Object] },
17:39:37 web.1  |      engine:
17:39:37 web.1  |       { clients: [Object],
17:39:37 web.1  |         clientsCount: 2,
17:39:37 web.1  |         pingTimeout: 60000,
17:39:37 web.1  |         pingInterval: 25000,
17:39:37 web.1  |         upgradeTimeout: 10000,
17:39:37 web.1  |         maxHttpBufferSize: 100000000,
17:39:37 web.1  |         transports: [Object],
17:39:37 web.1  |         allowUpgrades: true,
17:39:37 web.1  |         allowRequest: [Function],
17:39:37 web.1  |         cookie: 'io',
17:39:37 web.1  |         ws: [Object],
17:39:37 web.1  |         _events: [Object] } },
17:39:37 web.1  |   sockets:
17:39:37 web.1  |    [ { nsp: [Circular],
17:39:37 web.1  |        server: [Object],
17:39:37 web.1  |        adapter: [Object],
17:39:37 web.1  |        id: 'RfgXeMgHeP_9SQC5AAAC',
17:39:37 web.1  |        client: [Object],
17:39:37 web.1  |        conn: [Object],
17:39:37 web.1  |        rooms: [Object],
17:39:37 web.1  |        acks: {},
17:39:37 web.1  |        connected: true,
17:39:37 web.1  |        disconnected: false,
17:39:37 web.1  |        handshake: [Object],
17:39:37 web.1  |        _events: [Object] },
17:39:37 web.1  |      { nsp: [Circular],
17:39:37 web.1  |        server: [Object],
17:39:37 web.1  |        adapter: [Object],
17:39:37 web.1  |        id: '7TEjGJjWzxObulClAAAD',
17:39:37 web.1  |        client: [Object],
17:39:37 web.1  |        conn: [Object],
17:39:37 web.1  |        rooms: [Object],
17:39:37 web.1  |        acks: {},
17:39:37 web.1  |        connected: true,
17:39:37 web.1  |        disconnected: false,
17:39:37 web.1  |        handshake: [Object],
17:39:37 web.1  |        _events: [Object] } ],
17:39:37 web.1  |   connected:
17:39:37 web.1  |    { RfgXeMgHeP_9SQC5AAAC:
17:39:37 web.1  |       { nsp: [Circular],
17:39:37 web.1  |         server: [Object],
17:39:37 web.1  |         adapter: [Object],
17:39:37 web.1  |         id: 'RfgXeMgHeP_9SQC5AAAC',
17:39:37 web.1  |         client: [Object],
17:39:37 web.1  |         conn: [Object],
17:39:37 web.1  |         rooms: [Object],
17:39:37 web.1  |         acks: {},
17:39:37 web.1  |         connected: true,
17:39:37 web.1  |         disconnected: false,
17:39:37 web.1  |         handshake: [Object],
17:39:37 web.1  |         _events: [Object] },
17:39:37 web.1  |      '7TEjGJjWzxObulClAAAD':
17:39:37 web.1  |       { nsp: [Circular],
17:39:37 web.1  |         server: [Object],
17:39:37 web.1  |         adapter: [Object],
17:39:37 web.1  |         id: '7TEjGJjWzxObulClAAAD',
17:39:37 web.1  |         client: [Object],
17:39:37 web.1  |         conn: [Object],
17:39:37 web.1  |         rooms: [Object],
17:39:37 web.1  |         acks: {},
17:39:37 web.1  |         connected: true,
17:39:37 web.1  |         disconnected: false,
17:39:37 web.1  |         handshake: [Object],
17:39:37 web.1  |         _events: [Object] } },
17:39:37 web.1  |   fns: [],
17:39:37 web.1  |   ids: 0,
17:39:37 web.1  |   acks: {},
17:39:37 web.1  |   adapter:
17:39:37 web.1  |    { nsp: [Circular],
17:39:37 web.1  |      rooms:
17:39:37 web.1  |       { '5MGPNOdO4th_dOuZAAAA': [],
17:39:37 web.1  |         '64rUhxxp--4Qk1MqAAAB': [],
17:39:37 web.1  |         RfgXeMgHeP_9SQC5AAAC: [Object],
17:39:37 web.1  |         '7TEjGJjWzxObulClAAAD': [Object] },
17:39:37 web.1  |      sids:
17:39:37 web.1  |       { RfgXeMgHeP_9SQC5AAAC: [Object],
17:39:37 web.1  |         '7TEjGJjWzxObulClAAAD': [Object] },
17:39:37 web.1  |      encoder: {} },
17:39:37 web.1  |   _events: { connection: [Function] } }

Mi codigo es:

`` `` `` JAVASCRIPT

if (juego.scoreTeamTwo> juego.scoreTeamOne && juego.scoreTeamTwo> juego.scoreTeamThree && juego.scoreTeamTwo> juego.scoreTeamFour) {
game.winner = 2;
io.sockets.emit ('CTFEnd', juego);
}

// Solo mira si el equipo 1 ganó el juego y cuando lo hace emite CTFEnd y todos los demás datos del juego
`` `` ``

Comentario más útil

Esto probablemente sucedió porque estaba tratando de enviar un objeto con referencias circulares, lo que resultó en llamadas recursivas que excedieron el tamaño de la pila.

Todos 32 comentarios

Encontré una "solución" a mi problema. Puedo enviar cada pieza de datos esperada, pero NO funciona con objetos

Recientemente también he recibido ese error, la única diferencia es que solo me ocurre ocasionalmente. He estado probando toda la mañana y no he podido replicar el problema.

Para mí era que solo no podía emitir a todo el mundo, cuando el objetivo era demasiado grande.

@BenBals si el objeto es demasiado grande, entonces una solución decente es enviarlo en forma de cadena, es decir, ejecutar JSON.stringify() en él

Tengo otro trabajo alrededor, pero lo consideré.

: llorar: mirar en esto

tiene el mismo problema al emitir un objeto de tipo:
{éxito: archivo, contenido: archivo.contenido} donde archivo.contenido es el objeto Buffer y todas las demás propiedades del archivo son cadenas.

Tuve que agregar el contenido del campo directamente a los objetos porque hasBin () solo verifica el primer nivel de un objeto. Pero cuando intentó enviar el búfer, obtuvo 'Se superó la pila máxima de llamadas'

Puede replicar esto emitiendo el objeto de socket (al menos de una manera), por lo que (a continuación, sería servidor a -> cliente)

socket.emit('crash', {socket:socket});

Sin embargo, tengo curiosidad por saber si esto tiene una solución real.

¿Alguna actualización sobre ese tema?
EDITAR: Mi problema era que estaba tratando de enviar objetos recursivos.

Curiosamente, obtengo este mismo error cuando intento pasar mis datos de Firebase al lado del cliente.

Error

node_modules/socket.io/node_modules/has-binary-data/index.js:46

for (var key in obj) {
                ^
RangeError: Maximum call stack size exceeded

Lado del servidor

var DB = new Firebase('https://1234abcd.firebaseIO.com');
var USERS = DB.child("users");

io.sockets.on('connection', function(socket){

    socket.emit('test', {
        db: USERS
    });

});

Encuentra una solución...

Lo siento, pero mi chino no es tan bueno. ¿Sería tan amable de traducir esto al inglés?

Hice un Traductor de Google y sale "Encuentra la solución ..." ... apenas vale la pena responder. Para que conste, la solución es no pasar una cantidad tan grande de datos a través de socket.io ... es un socket que fue diseñado para respuestas rápidas y breves. Divida su respuesta o envíela a través de ajax. Cancelar la suscripción a este hilo.

Una cosa que podría hacer el código socket.io es iterar de forma asincrónica el objeto y sus propiedades, algo como:

var props = [];
var obj = { a: 1, b:2, c: { d: 3, e: 4 } };

function next_prop(callback){
  if (!props.length){
    setTimeout(callback);
    return;
  }
  var prop = props.shift();
  //do whatever with the prop, call parse_obj on it if it's an object
  setTimeout(next_prop);
}

function parse_obj(obj, callback){
  for (var i in obj){
    props.push(i);
  }
  setTimeout(function(){next_prop(callback);});
}

parse_obj(obj);

Por supuesto, este no es un código real que debe usar, porque debe haber un ajuste de funciones para cada objeto individual en caso de que estén anidados, de lo contrario, tendrá conflictos con el objeto que se está analizando.

También recibo ese error, mi código es como: "io.sockets.emit ('clave', datos);"
Intento simplificar el objeto "datos" y mantenerlo pequeño, y funcionó.
--Y, miro en el código src, encontré esto:

image_20150306180547

cuando su objeto "datos" tiene un atributo recursivo que hace referencia, este código falla.
p. ej. proto > proto > proto ...

+1 ¿Le gustaría al equipo central una versión asíncrona de la comprobación binaria? Puedo ayudar a conseguir esa configuración

Puedo reproducir el problema enviando el objeto socket :)

+1 IE11 muestra 'espacio sin pila' en _hasBinary.

Este error se me mostró cuando intentaba enviar todo el objeto de socket al cliente. Todo lo que _realmente_ necesitaba era socket.id por lo que el error desapareció cuando devolví un artículo más pequeño; en mi caso, socket.id lugar de todo el objeto socket

Esto probablemente sucedió porque estaba tratando de enviar un objeto con referencias circulares, lo que resultó en llamadas recursivas que excedieron el tamaño de la pila.

@LordMajestros ¡ Eso me lo arregló! Gracias

@GerbenHofman de nada

Enfrenté el mismo error en NodeJS v4.4.4 y socket.io v1.4.5.

En mi caso, sucede después del evento de desconexión.
Y sucede solo cuando llamé socket.emit más de 200.000 veces.

Si el número de llamadas socket.emit es de alrededor de 100.000, este error nunca sucederá.

El parámetro que uso con emit siempre es una cadena

¿Te ayuda esta información?

Solo para agregar a @shunjikonishi , he visto que esto sucedió tan pronto como envié exactamente 100,000 eventos a través de io.emit. Tengo 1 calcetín conectado, por lo que parece que 100.000 es un límite estricto.

Parece que este es un límite impuesto por Node (o el tiempo de ejecución de JavaScript) y Socket.io tiene una referencia a algo cada vez que llamas a emit, por lo que cuando alcanzas la emisión número 100,000, simplemente se cae.

Probado con Node 5.11.0 y Socketio 1.4.8. Mi versión de Node es diferente (así como mi sistema operativo, etc., realmente no tengo idea de dónde viene este 100,000) que @shunjikonishi, lo que puede explicar por qué llegué al límite en 100,000 mientras que él llegó a 200,000.

Ejecuté exactamente el mismo código usando ws.js y funcionó bien, superó las 100,000 emisiones de socket sin problema, así que tal vez sea un problema con Socket.io.

¿Existe alguna posibilidad de que Socket IO implemente una protección contra la emisión de datos recursivos y que fallen con este error? Una simple detección podría evitar que ocurra este error y emitir en su lugar un error más significativo, como "Puede estar intentando enviar datos circulares". Eso facilitaría la depuración.

Hay bastantes soluciones decentes para detectar datos circulares: https://stackoverflow.com/questions/14962018/detecting-and-fixing-circular-references-in-javascript

Una solución corta se basa en JSON.stringify para encontrar el problema:

function isObjectCircular(obj) {
    try {
        JSON.stringify(circularReference);
    } catch(err) {
        return (err.toString() === 'TypeError: Converting circular structure to JSON');
    }
    return false;
}

Más detalles: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value

@adamreisnz Le invitamos a hacer un PR;)

Siempre me toma desprevenido cuando alguien me menciona 5 meses después de que hice un comentario 😆

También encontré este error. Y es por eso que pierdo dos horas revisando todos mis códigos: <.
Creo que fue causado por un objeto de recursividad como A = {B: {C: A}}, y obviamente socket es un objeto de recursividad.
De hecho, supongo que sucedió porque en buffer.js, usan una recursividad para encontrar la longitud de los datos que desea enviar. Y luego obtenga el "tamaño máximo de pila de llamadas excedido". Si usan JSON.stringify () para obtener la longitud, habrá otro error claro sobre la "estructura circular". Por cierto, ¡tiene una mala palabra clave para google!

También me encontré con esto.

hasBin llenará la pila con un bucle recursivo si intenta enviar un objeto que tiene una referencia circular.

Joder, veo que hay un PR que ha estado abierto durante 2 años que solucionaría esto:

@dustingraham, la solución se ve muy bien, aunque no estoy seguro de las implicaciones de rendimiento.

Además, incluso si ya no incluye el método hasBinary , me temo que el método JSON.stringify que se llama más adelante en el código seguirá arrojando un error:

> var a = {};
undefined
> var b = { a: a };
undefined
> a.b = b
{ a: { b: [Circular] } }
> JSON.stringify(a)
Thrown:
TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

karmac2015 picture karmac2015  ·  3Comentarios

adammw picture adammw  ·  4Comentarios

gCurtisCT picture gCurtisCT  ·  4Comentarios

jloa picture jloa  ·  4Comentarios

MyMomSaysIAmSpecial picture MyMomSaysIAmSpecial  ·  4Comentarios