首页 > 解决方案 > 在 Node.js 中创建对象是否有推荐的方法?

问题描述

我知道在 PHP 中为每个请求创建对象并在处理完成时销毁。

在 Java 中,根据配置,对象可以保留在内存中,并且可以与单个用户关联(通过服务器会话)或在多个用户之间共享。

Node.js 中对此有一般规则吗?

我看到许多项目在入口脚本中实例化了所有应用程序对象,在这种情况下,它们将在请求之间共享。

其他人会将对象创建保留在函数内部,因此 AFAIK 对象在处理每个请求后都会被销毁。

每种方法的缺点是什么?显然,应该考虑内存使用和信息共享之类的事情,但是对于 Node.js,还有其他我们应该注意的事情吗?

标签: node.jsobjectarchitecturerequest

解决方案


Javascript 没有与给定请求相关联的对象。该语言是垃圾收集的,当没有更多对它们的引用并且没有代码可以访问它们时,所有对象都将被垃圾收集。这与请求处理程序完全无关。

所以 AFAIK 对象在处理每个请求后都会被销毁。

不,Javascript 中对象的生命周期与请求完全无关。

相反,请考虑函数范围。如果您在请求处理程序中创建一个对象并在该请求处理程序中使用它并且不将它存储在创建对该对象的长期引用的地方,那么就像 Javascript 中的任何其他函数一样,当该请求处理程序函数完成并返回时并且没有更多的异步操作仍在进行中,那么在该函数中创建的任何未存储在其他范围内的对象都将被垃圾收集器清除。

请求处理程序的规则与语言中任何其他函数调用的规则完全相同。

所以,请忘记你对 PHP 的任何了解,因为它的特定于请求的架构只会在 Javascript/node.js 中搞砸你。node.js 中没有这样的东西。

相反,将 node.js 服务器视为一个带有垃圾收集器的长时间运行的进程。所有创建的对象在它们不再被实时代码访问时都会被垃圾回收(例如,没有任何代码可以访问的对它们的实时引用)。无论对象是在服务器启动时、在服务器上的请求处理程序中、在服务器上的循环计时器中还是在服务器上的任何其他事件中创建的,这都是相同的。该语言有一个垃圾收集器,它在任何地方都工作相同,并且对服务器请求没有特殊行为。

在 node.js 服务器中做事的常用方法是在请求处理函数(或在它调用的任何函数中)创建作为局部变量的对象,或者甚至可能偶尔分配为requestorresponse对象的属性(中间件通常会这样做这)。由于在该函数调用完成时,所有内容都限定为请求链中的函数调用,因此您在这些函数中作为局部变量创建的内容将符合垃圾收集的条件。

通常,除了有目的的长期存储(会话状态、数据库连接或其他服务器范围的状态)之外,您不会在请求处理程序之外使用许多更高范围的变量。

Node.js 中对此有一般规则吗?

不是你问的那种意义上的,因为 Javascript 实际上只是声明变量的范围,然后从那里进行垃圾收集,但我将在下面提供一些指导方针。

如果数据存储在比请求处理程序更高的范围(模块范围或全局范围)中,那么它可能会持续很长时间,因为未来的请求处理程序可以访问一个持久引用,因此不会被垃圾收集。

如果对象是在请求处理程序中创建和使用的,并且没有附加到任何更高的范围,那么当函数执行完成时,语言会自动对它们进行垃圾收集。

会话框架通常会创建一种特定的机制来存储服务器端状态,该状态在每个用户的基础上持续存在于服务器上。流行的 node.js 会话管理express-session器正是这样做的。在那里,您遵循会话框架的规则,了解如何从每个用户的会话中存储或删除数据。这不是真正的语言功能,因为它是语言中构建的特定库。甚至会话管理也依赖于垃圾收集器。需要时,数据会保留在会话管理器中,因为对数据的持久引用使其可用于未来的请求。

node.js 没有内置于语言或环境中的“每个用户”或“每个请求”数据。会话管理器通过生成可在每个用户基础上请求或访问的持久数据,人工构建“每个用户”数据。

node.js 的一些一般规则:

  1. 在您的头脑和设计中定义哪些数据是特定请求处理程序的本地数据,哪些数据用于长期存储,哪些数据用于用户特定的会话。你应该很清楚这一点。

  2. 永远不要将特定于请求的变量放入任何其他请求处理程序可以访问的更高范围,除非这些是有目的的共享变量,旨在由多个请求访问。在请求之间意外共享变量会产生并发问题和竞争条件以及非常难以追踪的服务器错误,因为一个请求可能会在工作时写入该变量,然后另一个请求可能会出现并写入它,从而破坏了第一个请求正在处理中。将这些特定于请求的变量保留在请求处理程序的本地(对于请求处理程序的函数而言是本地的),这样就永远不会发生。

  3. 如果您要存储数据以供长期使用(超出特定请求的生命周期),这通常意味着将其存储在模块范围变量或全局范围变量中(通常不应使用全局范围变量),那么非常非常小心数据的存储和访问方式,以避免竞争条件或不一致的状态,这可能会混淆其他请求处理程序读取/写入该数据。node.js 使这更简单,因为它以单线程方式运行您的 Javascript,但是一旦您的请求处理程序进行某种异步函数调用(如数据库调用),那么其他请求处理程序就会运行,因此您必须小心修改跨异步边界的共享状态。

我看到许多项目在入口脚本中实例化了所有应用程序对象,在这种情况下,它们将在请求之间共享。

在使用 Express 框架的 Web 服务器示例中app,所有请求都可以访问一个对象。唯一特定于请求的变量是由 Web 服务器框架创建并传递给您的请求处理程序的对象requestresponse这些对于每个新请求都是唯一的。所有其他服务器状态均可被所有请求访问。

每种方法的缺点是什么?

如果您要求将 Apache/PHP Web 服务器模型与 node.js/Express Web 服务器模型进行比较,这是一个非常大的问题。它们是非常不同的架构,并且该主题之前已被广泛讨论和辩论。我建议您对该主题进行一些搜索,阅读以前写过的内容,然后就您不太了解或需要澄清的事情提出更具体的问题。


推荐阅读