Node.js 一个 Socket.IO 程序的疑问

daqing · 2015年08月13日 · 最后由 daqing 回复于 2015年08月14日 · 8568 次阅读

最近写了一个简单的 Socket.IO 程序,代码如下:

var io = require('socket.io')(8801);
var redis = require('reds');

io.on('connection', function(socket) {
    var client = redis.createClient();
    client.on('message', function(channel, data) {
        var message = JSON.parse(data);
        io.emit(message['type'], message);
    });

    client.subscribe('node');
});

这段代码工作正常,但我的疑惑是:在connection回调函数执行完以后,client变量不就被垃圾回收了吗?然后到 redis 的连接应该会断开了啊,为什么实际上没有断开呢?

@daqing connection 回调函数中你用到了 redis 这个方法外的环境变量。其实这个回调函数已经是形成一个闭包,回调方法中的所有成员变量都会一直存在了 (也用到了 io). 回调方法的已经将当前的 Execution Context 和回调方法外的 Execution Context 这两个 Context 放到他的 scope chain 中去了。

Execution Context, Scope Chain

Javascript 不是很熟悉,但是这个应该是共通的。传入的 function 其实就是一个 closure,是带有当前 scope 的 binding 的,比如这里的io, redis, connection 触发时,调用传入的 function,创建一个 client,所以其实每次调用的时候都是一个新的 client。

@yanguango 其实如果传入的 function 里面没有调用方法外的环境变量的话还是不存在闭包的,只是 function first class 传入一个 function 作为 param 罢了。

不过,这个每次 connection 回调函数被触发,应该每次都被创建了一个新的 client 实例,并且都因闭包形成一直存在于内存中

client 应该是不会被 GC 的,毕竟在用。

connection 事件中创建的 client 会去注册一些回调函数,为了保持状态,注册回调函数的时候会把 this 绑定进去,类似于

sock.on("data", client.ondata.bind(client));

这样这个回调函数就会有 client 的引用,所有 client 不会被回收。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号