Efficiency with JavaScript Callbacks

2019-07-15 13:13发布

问题:

I just wanted to confirm a suspicion of mine.

I stumbled across an article which recommended using Socket.io in the following fashion:

var app = require('express').createServer()
var io = require('socket.io').listen(app);

app.listen(8080);

// Some unrelated stuff

io.sockets.on('connection', function (socket) {
    socket.on('action1', function (data) {
        // logic for action1
    });

    socket.on('action2', function (data) {
        // logic for action2
    });

    socket.on('disconnect', function(){
        // logic for disconnect
    });
});

I feel like the following would be a better use of resources:

var app = require('express').createServer()
var io = require('socket.io').listen(app);

app.listen(8080);

// Some unrelated stuff

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

function action1(data) {
    // logic for action1
}

function action2(data) {
    // logic for action2
}

function disconnect() {
    // logic for disconnect
}

My feeling is that although the anonymous function that handles the connection event is only created in memory once, the anonymous functions that handle action1, action2, and disconnect are created in memory for every socket connection. The issue with the second approach is that socket is no longer in scope.

So firstly, is my suspicion about the creation of functions true? And secondly, if so is there a way to get socket in scope for the named functions?

回答1:

Using a closure helps to keep the scope clean:

io.sockets.on('connection', function () {
    function action1(data) {
        // logic for action1
    }
    function action2(data) {
        // logic for action2
    }
    function disconnect() {
        // logic for disconnect
    }
    return function (socket) {
        socket.on('action1', action1);
        socket.on('action2', action2);
        socket.on('disconnect', disconnect);
    }
}()); // <- note the immediate function call 

To your questions:

So firstly, is my suspicion about the creation of functions true?

Yes. The closure approach above prevents this, the callback functions are created only once. Plus: all see the correct parent scopes.

And secondly, if so is there a way to get socket in scope for the named functions?

The socket will be available as this in the callbacks.



回答2:

You're correct, that the anonymous methods are created for each connection - and if you don't need scope, then the second method does avoid that. If you need the socket scope there's no real way to avoid it. If you want to keep the methods external (for some other reason) and still keep scope, you could always:

//...
socket.on('action1', function(){
  action1.apply( socket, arguments );
} );
//... and so forth.

But that has you back to creating a method signature for each connection, so I'm not sure what you'd be gaining.