我是否需要为每个具有等待结果回调的方法关闭

Do I need closure for every single methods that has a wait-for-result callback?

本文关键字:回调 结果 等待 方法 是否      更新时间:2023-09-26

我正在使用 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 用户 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

我认为你的第一个例子应该可以正常工作。例如,请参阅以下内容:

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

你必须把它包装成IIFE,就像这样:

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

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

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

我个人更喜欢第二种方法。

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

function test(i) {
  setTimeout(function() {
    console.log(i);
  }, 1000*i);
}
test(0);
test(1);

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