Socket.io: RangeError:最大コールスタックサイズを超えました

作成日 2014年07月04日  ·  32コメント  ·  ソース: socketio/socket.io

私は `ìo.sockets.emit( 'hey'、data);を呼び出しています。 and it will crash with RangeError:最大コールスタックサイズが. 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``を超えました。

問題がどこにあるのかわかりません。 使用する直前にio.socketsログに記録しようとしましたが、次のように出力されます。

{ 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] } }

私のコードは次のとおりです。

`` `` `` JAVASCRIPT

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

//チーム1がゲームに勝ったかどうかを確認しているだけで、勝った場合はCTFEndと他のすべてのゲームデータが送信されます
`` `` `` ``

最も参考になるコメント

これはおそらく、循環参照を使用してオブジェクトを送信しようとしたために、スタックサイズを超える再帰呼び出しが発生したために発生しました。

全てのコメント32件

私の問題の「解決策」を見つけました。 スペシャライズされたすべてのデータを送信できますが、オブジェクトでは機能しません

私は最近そのエラーも受けていますが、唯一の違いはそれが私にとってたまにしか起こらないということです。 午前中ずっとテストを行っていましたが、問題を再現できませんでした。

私にとっては、objが大きすぎると、誰にでも放出できなかったということでした。

@BenBalsオブジェクトが大きすぎる場合、適切な回避策は、文字列の形式でオブジェクトを送信することJSON.stringify()します。

別の回避策がありましたが、それを考慮しました。

:cry:これを調べて

タイプのオブジェクトを発行するときに同じ問題があります。
{success:file、content:file.content}ここで、file.contentはBufferオブジェクトであり、fileの他のすべてのプロパティは文字列です。

hasBin()はオブジェクトの最初のレベルのみをチェックするため、フィールドコンテンツをオブジェクトに直接追加する必要がありました。 しかし、バッファを送信しようとすると、「最大コールスタックを超えました」というメッセージが表示されました。

ソケットオブジェクトを(少なくとも一方向に)発行することでこれを複製できます(以下はサーバーから->クライアントになります)

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

しかし、これに実際の修正があるかどうか知りたいです。

その問題に関する更新はありますか?
編集:私の問題は、再帰オブジェクトを送信しようとしていたことでした。

興味深いことに、Firebaseデータをクライアント側に渡そうとすると、これと同じエラーが発生します。

エラー

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

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

サーバ側

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

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

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

});

解決策を探し...

申し訳ありませんが、私の中国語はそれほど上手ではありません。 これを英語に翻訳していただけませんか。

グーグル翻訳をしました、そしてそれは「解決策を見つけてください...」に出てきます...ほとんど答える価値がありません。 記録のために、解決策は、socket.ioを介してそのような大量のデータを渡さないことです...それは、迅速で短い応答のために設計されたソケットです。 応答を分割するか、ajax経由で送信します。 このスレッドの購読を解除します。

socket.ioコードで実行できることの1つは、オブジェクトとそのプロパティを非同期的に反復すること

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

もちろん、これは実際に使用する必要のあるコードではありません。ネストされている場合は、個々のオブジェクトごとに関数をラップする必要があるためです。そうしないと、解析されるオブジェクトと競合することになります。

私もそのエラーが発生します。私のコードは次のようになります: "io.sockets.emit( 'key'、data);"
「データ」オブジェクトを単純化して小さくしようとすると、うまくいきました。
-そして、私はsrcコードを調べて、これを見つけました:

image_20150306180547

「データ」オブジェクトに再帰的な属性参照がある場合、このコードはクラッシュします。
例: proto > proto > proto ..。

+1は、コアチームがバイナリチェックの非同期バージョンを好むだろう私はそのセットアップを取得するのを助けることができます

ソケットオブジェクトを送信することで問題を再現できます:)

+1 IE11は、_hasBinaryに「スタックスペースが不足しています」と表示されます。

このエラーは、ソケットオブジェクト全体をクライアントに送り返そうとしたときに表示されました。 私が_本当に_必要としたのはsocket.idだったので、小さなアイテムを返送するとエラーは消えました—私の場合、 socketオブジェクト全体ではなくsocket.id

これはおそらく、循環参照を使用してオブジェクトを送信しようとしたために、スタックサイズを超える再帰呼び出しが発生したために発生しました。

@LordMajestrosそれは私のためにそれを修正しました! ありがとう

@GerbenHofmanどういたしまして

NodeJSv4.4.4とsocket.iov1.4.5で同じエラーが発生しました。

私の場合、切断イベントの後に発生します。
そして、それは私がsocket.emit 200,000回以上呼び出したときにのみ起こります。

socket.emitの呼び出し回数が約100,000の場合、このエラーは発生しません。

emit使用するパラメーターは常に文字列です

この情報は役に立ちますか?

@shunjikonishiに追加する正確に100,000のイベントを送信するとすぐに、これが発生するのを確認しました。 靴下を1つ接続しているので、100,000はハードキャップのようです。

これはノード(またはJavaScriptランタイム)によって課せられた制限のようであり、Socket.ioはemitを呼び出すたびに何かへの参照を保持しているため、100,000番目のemitに達するとフォールオーバーします。

Node5.11.0およびSocketio1.4.8でテスト済み。 私のNodeのバージョンは@shunjikonishiとは異なります(オペレーティングシステムなど、実際にはこの100,000がどこから来たのか

私はws.jsを使用してまったく同じコードを実行しましたが、問題なく動作し、100,000ソケットを超えても問題はなかったので、Socket.ioに問題がある可能性があります。

Socket IOが、このエラーから発行されて失敗する再帰データに対するガードを実装する可能性はありますか? 単純な検出により、このエラーの発生を防ぎ、代わりに「循環データを送信しようとしている可能性があります」などのより意味のあるエラーを発行できます。 これにより、デバッグが容易になります。

循環データを検出するための適切なソリューションはかなりあります: https

1つの短い解決策は、JSON.stringifyに依存して問題を見つけます。

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

詳細: https

@adamreisnzあなたはPRをすることを歓迎します;)

私がコメントした5か月後に誰かが私に言及したとき、それは常に私を不意を突かせる😆

私もこのエラーに遭遇しました。 そのため、コード全体をチェックするのに2時間を無駄にしています:<。
これはA = {B:{C:A}}のような再帰オブジェクトが原因だと思います。明らかに、ソケットは再帰オブジェクトです。
実際、buffer.jsでは、再帰を使用して送信するデータの長さを見つけるために発生したと思います。 次に、「最大呼び出しスタックサイズを超えました」を取得します。 JSON.stringify()を使用して長さを取得すると、「循環構造」に関する別の明らかなエラーが発生します。 ちなみに、グーグルには悪いキーワードがあります!

私もこれに出くわしました。

hasBinは、循環参照を持つオブジェクトを送信しようとすると、スタックを再帰ループで埋めます。

シャック、私はこれを修正する2年間開いているPRがあると思います:

@dustingrahamの修正は見栄えがしますが、パフォーマンスへの影響についてはよく

また、 hasBinaryメソッドがスローされなくなったとしても、コードの後半で呼び出されるJSON.stringifyメソッドがエラーをスローするのではないかと心配しています。

> 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>)
このページは役に立ちましたか?
0 / 5 - 0 評価