Node.js:什么是我们在asynchronous编程中回复正确请求的保证?

在所有的大部分node.js教程中,我可以看到这种编码模式。

 app.get('/user', function (req, res) { User.findById(req.body.id, function(err, user) { if (err) throw err; res.send(user); }); }); 

现在这条线res.send(user)吓我res.send(user)User.findByIdasynchronous ,这个api的终点可能会同时发生,我们在回复req的时候有什么保证。

截至目前我正在创buildclosure以保持variables值。

 app.get('/user', function (req, res) { User.findById(req.body.id, function(res){ return function(err, user) { if (err) throw err; res.send(user); } }(res)); }); 

解决这个问题的最好方法是什么?

您不需要为reqres添加closures保护。 它们已经被正确地定义为一个callback,并且不被其他请求中的代码共享或访问。

app.get()函数调用已经为reqres对象创build了一个闭包。 因此,无论在任何地方进行多lessasynchronous编码,在该callback中或从该callback中调用并传递这些参数的任何代码都能保证获得正确的对象。

 app.get('/user', function (req, res) { // This is already a unique closure right here with unique copies of // the req and res arguments. These arguments cannot be accessed // by any other request or by any code out of this scope // unless you copy them yourself to some shared location // with concurrency access issues User.findById(req.body.id, function(err, user) { if (err) throw err; res.send(user); }); }); 

唯一必须正确发生的事情是node.js不会重复使用这些reqres对象来处理asynchronous处理时可能发生的其他请求。 而且,它保证。 reqres是为每个请求创build的。

此外,除非你以某种方式不恰当地共享它(像在一个共享的模块级别variables中填充它),否则甚至没有办法从一个请求获得对另一个请求的请求或res访问。 所以,只要你只使用reqres直接从词法范围的callback中,或者将它们传递给你正在调用的函数,而且你的代码实际上不会将它们保存在有并发访问问题的地方,那么就没有问题。

所以,总结一下。 node.js本身没有reqres对象的任何并发问题。 所以,只要你没有通过将reqres存储在你自己的代码中存在并发访问问题的共享位置来创build问题,这不是问题。


错误的代码示例

只是为了告诉你什么错误的代码看起来会造成问题:

 var _res; app.get('/user', function (req, res) { _res = res; User.findById(_req.body.id, function(err, user) { if (err) throw err; _res.send(user); }); }); app.get('/account', function (req, res) { _res = res; User.findById(req.body.account, function(err, account) { if (err) throw err; _res.send(account); }); }); 

在这里,代码将res分配给一个更高范围的共享variables,然后在asynchronous调用之后尝试使用它。 这会很糟糕,并且会造成并发问题。 但是,这不是node.js本身的问题,而是代码错误的问题,它不知道适当的并发devise。 而且,没有理由将asynchronous操作中使用的variables复制到更高和共享范围。 如果它需要在其他地方,它应该作为parameter passing,因为它会保持每个请求的唯一性。


以下是关于“Javascript词法作用域”的一些阅读参考。

你应该知道的Javascript范围

MDN:词汇范围和closures

你不知道JS:范围和闭包

想要了解的Javascript范围的一切

你的尝试是不正确的和不必要的。 在这种情况下,词汇范围将照顾你认为是一个问题。

 app.get('/user', function (req, res) { // <- the `res` here User.findById(req.body.id, function(err, user) { if (err) throw err; res.send(user); // is the same `res` here }); }); 

由于通过作为callback传递的函数的定义而创build的已经存在的闭包。

我认为你的恐慌是没有根据的。 当请求到达时,每个请求都会自己引用到您传递给它的callback函数。 在这种情况下是处理响应的那个。 该函数获取res对象,然后由于findById中的词法作用域而将该对象用于下一个传递给findByIdcallback函数。

 app.get('/user', function (req, res) { User.findById(req.body.id, function(err, user) { if (err) throw err; res.send(user); // res here is unique for every new request,no need to worry :) }); });