Agustin Castro
Agustin Castro

Reputation: 459

socket.io inside of loop doesn't work

I'm trying to emit events inside of loop. But, just launch the first event(start) and once.

The behavior in console must be: a emit event start emit event finish b emit event start emit event finish

another again

a emit event start emit event finish b emit event start emit event finish

However, it's behave the next way:

a emit event start b

another again

a b

Why the event only is emit once?

var server = require('http').createServer();
var io = require('socket.io')(server);
var sleep = require('sleep');

io.on('connection', function(socket){
  socket.on('disconnect', function(){});
});

server.listen(3000);




function B() {

    this.bundles = ['a', 'b'];
    this.currentPosition = 0;

    this.run = function() {
        var bundle = this.bundles[this.currentPosition];

        console.log(bundle);


        io.emit('start', { 'bundle': bundle });
        io.emit('finish', { 'bundle': bundle });

        ++this.currentPosition;
        if (this.bundles[this.currentPosition] === undefined) {
            this.currentPosition = 0;
        }

        sleep.sleep(2);
        this.run();
    }
}


//wait to start server
setTimeout(function(){ 
    var b = new B();
b.run();
 }, 6000);

Upvotes: 1

Views: 2887

Answers (1)

ChevCast
ChevCast

Reputation: 59213

Try changing it to a setInterval.

http://codepen.io/Chevex/pen/zGdQXQ

    this.run = function() {
        var bundle = this.bundles[this.currentPosition];

        console.log(bundle);


        io.emit('start', { 'bundle': bundle });
        io.emit('finish', { 'bundle': bundle });

        ++this.currentPosition;
        if (this.bundles[this.currentPosition] === undefined) {
            this.currentPosition = 0;
        }
    }
    setInterval(this.run.bind(this), 2000);

The interval will run every 2 seconds and won't flood your call stack.

Whenever you call a function from another function, you build a call stack.

function foo() {
  bar();
}
function bar() {
  console.log('end of stack, returning');
}
foo();

The above code would build a stack like this:

-> event loop
  -> foo
    -> bar
      -> console.log

Then as the functions start returning, they pop off the stack one by one. What this means is that when you call a function from within itself, you will definitely exhaust the call stack if the recursive calls never stop.

function foo() {
  foo();
}
foo();

This would result in an ugly call stack that will run your memory dry.

-> event loop
  -> foo
    -> foo
      -> foo
        -> foo
          -> foo
            -> etc...

You can see that the JavaScript engine even tries to detect when this is happening and throw an exception. The engine doesn't always catch these though if the recursive stack is more complicated. It's best to just avoid it and stick to setInterval.

By using setInterval you're registering a function with node and telling it to fire it each time a certain number of milliseconds has passed. This saves your call stack because the function is fired, returns, and then starts again when the node event loop detects that n milliseconds has passed again. No infinite call stack that would result in a...

...Stack Overflow

PS - Now you understand this site's own logo. It's a call stack :)

Upvotes: 5

Related Questions