对于具有等待结果回调的每个方法,我是否需要闭包?

时间:2016-02-20 04:26:15

标签: javascript node.js closures

我正在使用socket.io和MySQL数据库工作在nodejs服务器上,当我意识到当数据从数据库检索很慢时,数据可能随时发生变化。 比方说,例如,在每个套接字连接上,我想在数据库发出X数据时查询数据库中的用户信息。

io.on('connection', function(socket) {
    console.log('User connected');
    socket.on('fetchTable', function(data) {
        var number = data.number;
        database.getTable(number, function(error, result) {
            // We'll take it that result is constant for both: 1
            socket.emit('fetchTableResult', result + number);
        });
    });
});

如果2个用户在同时连接(用户1的号码:1,用户2的号码:2),用户1请求数据库 BEFORE 用户2但是数据库要为用户1和已处理用户2的数据返回结果太慢。返回的数据会有所不同吗?两个用户都将获得'3'作为'fetchTableResult'数据吗?套接字现在不是用户2的套接字吗?

解?

io.on('connection', function(socket) {
    console.log('User connected');
    socket.on('fetchTable', function(data) {
        var number = data.number;
        (function(socket, number) {
            database.getTable(number, function(error, result) {
                // We'll take it that result is constant for both: 1
                socket.emit('fetchTableResult', result + number);
            });
        })(socket, number)
    });
});

如果是这种情况,如果在database.getTable内,我有另外一种方法,例如获取网站的HTML内容需要花费一些时间,我是否真的需要另一个封闭内容?

例如:

io.on('connection', function(socket) {
    console.log('User connected');
    socket.on('fetchTable', function(data) {
        var number = data.number;
        (function(socket, number) {
            database.getTable(number, function(error, result) {
                // We'll take it that result is constant for both: 1
                (function(socket, result) {
                    // fetch website html data
                    socket.emit('fetchTableResult', result + number);
                })(socket, result)
            });
        })(socket, number)
    });
});

参考:https://github.com/loverajoel/jstips/blob/gh-pages/_posts/en/2016-02-03-implementing-asynchronous-loops.md

1 个答案:

答案 0 :(得分:1)

我认为你的第一个例子应该可以正常工作。请参阅此示例:



document.addEventListener("click", function(event) {
  var x = event.x;
  setTimeout(function() {
    console.log(x);
  }, 1000);
});




尝试在短时间内点击两个不同的地方。正如预期的那样,您将得到不同的结果。

当你在循环中执行异步函数时,你需要一个闭包(实际上是一个IIFE),例如,这不会按预期工作:



for (var i = 0; i < 2; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000*i);
}
&#13;
&#13;
&#13;

你必须把它包裹起来IIFE,就像这样:

&#13;
&#13;
for (var i = 0; i < 2; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, 1000*i);
  }(i));
}
&#13;
&#13;
&#13;

或将i绑定到回调,如下所示:

&#13;
&#13;
for (var i = 0; i < 2; i++) {
  setTimeout(function(i) {
    console.log(i);
  }.bind(null, i), 1000*i);
}
&#13;
&#13;
&#13;

就个人而言,我更喜欢第二种方法。

但是,当您多次调用异步函数时,您不需要IIFE,因为此函数本身就是一个闭包。例如:

&#13;
&#13;
function test(i) {
  setTimeout(function() {
    console.log(i);
  }, 1000*i);
}

test(0);
test(1);
&#13;
&#13;
&#13;

每次调用test()时,都会创建另一个范围,因此i变量不会被覆盖,并且按预期工作。