Node.js,express和对象实例化在路由端点内部/外部

时间:2017-12-05 23:00:01

标签: javascript node.js ecmascript-6 promise

我有一个关于对象实例化的问题。现在我有一个相当大的应用程序设置,在后端实现RESTful端点。

我想知道什么是对象实例化的“最佳”方式,以及垃圾收集器如何受到我的影响。

举例如下:

const MyClass = require('../controllers/myClassController');
const router = require('express').Router();

router.get('/', (req, res) => {
    console.log('GET request at api/someEndPoint');

    const myClass = new MyClass();
    myClass.doSomePromise()
        .then(() => {
            res.end();
        })
        .catch((err) => {
            res.status(500).end();
        });
});

这里,对象在路径路径实现中实例化。

现在,以此为例:

const MyClass = require('../controllers/myClassController');
const router = require('express').Router();

const myClass = new MyClass();

router.get('/', (req, res) => {
    console.log('GET request at api/someEndPoint');

    myClass.doSomePromise()
        .then(() => {
            res.end();
        })
        .catch((err) => {
            res.status(500).end();
        });
});

这里,对象被实例化为路径路径实现的OUTSIDE。在我看来好像这会在应用程序的生命周期中无限期地持续存在,而第一个例子,变量myClass将被清除。

所以我真的很想知道:

  1. 我是否正确地思考这个问题?
  2. 我有理由相对于另一种做一种方法吗?似乎如果我选择了选项2,我可能只是在类本身上制作static方法......
  3. 每种方法的一般优点/缺点是什么?

    我觉得在我的脑海中,我正在为战斗而战,事情没有得到正确的清理,一方面比另一方面更好,因为有多少交通,比赛条件避免等等!

2 个答案:

答案 0 :(得分:0)

  1. 是的,你的想法是合法的。尽管像物体实体这样的东西可能是微观优化。

  2. 正如Bergi在评论中已经提到的,如果你不需要,你不应该在你的路线内重建或处理任何东西。您始终需要记住,路由处理程序中的代码是在每个到达此路由的请求上执行的。

  3. 所以你真正要问的是:我应该每个应用程序生命周期执行const myClass = new MyClass();一次,或者每秒可能执行数千次。{1}}只有在每次必须处理对此路由的请求时才真正需要创建类的新实例时,才能回答。可能你不需要每次都创建一个实例。因此,为了避免不必要的工作,请将其置于路由处理程序之外。
  4. 从#3开始,由于上述原因,没有真正的pro / con列表。如果你可以避免你的路由处理程序内的instanation,那么避免它!

答案 1 :(得分:0)

真的很简单。

  1. 如果您在整个应用程序期间只需要一个对象,并且您可以将该对象用于任何恰好需要使用它的请求,那么它就是'一个"应用程序周期"对象的类型。在初始化时创建一个,存储其实例(可能作为模块级变量)并从此使用它。作为一个例子,如果你有一些设计用于许多请求处理程序的缓存对象,那么你想要创建一次然后保留它并且每次都使用相同的对象使用它的请求处理程序。另一个例子是,一些应用程序在启动时创建一个与其主数据库的连接,然后所有其他请求都可以使用该连接。

  2. 如果您需要一个可以使用它的每个请求的新对象,那么在请求处理程序中创建它并让正常的垃圾收集在请求时进行清理。完成。例如,如果您需要创建一个Date()对象以便在请求期间测量一些持续时间,最简单的实现将在请求处理程序中创建一个new Date()对象,将其用于您需要使用的内容它是for for然后让GC在请求完成后处理它。

  3. 如果您需要为每个请求设置一个独立的对象,以便多个请求处理程序在"在飞行中"同时,您需要确保每个请求处理程序都有自己的对象,并且没有共享或冲突。

  4. 还有混合模型(通常以这种方式作为性能优化),您可以在其中创建对象池,然后每个需要一个对象的请求可以检查一个",使用它一段时间,然后在完成后将其返回池中。当一小部分对象通常可以满足服务器的需求时,这通常可以节省从头开始重建对象的时间。有些数据库使用这个" pool"数据库连接的模型。请求可能只是从池中获取数据库连接,进行查询,然后将连接返回到池中,而不是为每个想要进行查询的请求创建与数据库的新连接。

  5. 在node.js内部,它为磁盘I / O实现的某些部分使用线程池。类似的概念。

      

    我想知道"最好的"对象实例化的方式,以及垃圾收集器如何受到我的影响。

    最好的方法是选择与使用情况相匹配的实例化模型。在上面的选项1中,对象可能会在整个应用程序周期中存储而根本不会存储。在选项2和3中,将为每个请求创建和GCed对象。你不应该担心创建和使用对象,然后让它GC。这就是语言如何设计用于那些没有持久持久状态并且应该保持更长时间的东西。

      

    我有理由相对于另一种方法做一种方法吗?似乎如果我选择了选项2,我不妨在类本身上制作静态方法......

    如果对象中没有特定于请求的状态,并且如果有多个请求处理程序同时尝试使用该对象,则对象本身的状态不会遇到麻烦,那么您真的只需要一个全局服务任何想要使用它的请求处理程序都可以使用它。如果你将它实现为你创建的对象,存储实例,然后在该实例上调用传统方法,或者将其实现为更多实例化自身的单例,并且只调用函数或静态方法,那么由您自己决定。它。这只是编码风格的差异,而不是功能差异。

      

    每种方法的一般优点/缺点是什么?

    通常,您需要尽可能多的封装和本地状态。无需将特定于请求的内容放入共享全局变量中。针对特定请求计算或计算的事物属于请求处理程序逻辑的内部。因此,只需按照上面的四个问题来确定对象是属于请求处理程序的本地对象还是在更高的作用域中共享。如果你能通过保持本地化来实现目标,那么这通常更清洁,更安全,更灵活。

      

    我觉得在我的脑海里,我正在战斗,事情没有得到正确的清理,在有多少交通,避免竞争条件等方面,一种方式比另一种方式更好。 !

    GC为您负责清理工作。你可以依靠它。只要您不持久地将对象的引用存储在具有持久范围的变量中,垃圾收集就会很好地为您清理。这就是语言的设计方式。你不应该害怕它。如果,或许你来自非GC语言,如C或C ++,你可能会过度思考这个问题。 GC就是你的朋友。非常,非常非常偶尔你可能需要进行一些性能调整,以便更多地了解你要求GC做多少,但在你真正实际看之前,这几乎不应该是你担心的事情。发现你有一些需要特殊优化的东西。

    避免请求处理程序之间竞争条件的最简单方法是不在请求处理程序之间共享任何状态。如果处理给定请求所需的所有内容都是在本地创建和使用的,并且永远不会对任何其他请求处理程序可用,那么您绝对可以避免多个请求处理程序之间的竞争或共享条件。一般来说,从那里开始,因为这是最简单和最安全的。然后,如果您发现需要对性能进行优化,那么您可以探索某些类型对象的某些共享或缓存,并且您必须仔细执行此操作以避免引入共享问题。但是,您很少开始尝试这样做,因为大部分时间都不需要额外的复杂性。