V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xihua2018
V2EX  ›  Node.js

如何以 Node.js 方式编写单例

  •  
  •   xihua2018 · 361 天前 · 1003 次点击
    这是一个创建于 361 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如何以 Node.js 方式编写单例

    文 / Victor - AfterShip

    译 / 吴天成 - AfterShip

    问题描述

    以下面这种方式,写单例很容易:

    let someModule
    
    async getSomeModule() {
        if (!someModule) {
            someModule = await someAsyncOperationsToInitializeModule()
        }
        return someModule
    }
    
    module.exports = getSomeModule
    

    通常以这种方式使用它:

    // in async function
    const getSomeModule = require('./getSomeModule')
    const someModule = await getSomeModule()
    

    除非你希望将模块的加载延迟到初次运行时,否则不鼓励这种方式。

    因为,这将带来很多没必要的分支代码(例如,if statement ),实际上我们希望避免这种代码。而且使用 let 语法将会中断静态代码分析,导致 IDE 不能正确推导出 someModule 的类型。

    解决方案 A

    请注意,node 的模块系统默认为单例(模块在第一次 required 的时候将会被缓存[1])。所以一旦一个 promiseresolved 并导出,无论谁 require(加载) 模块,它将始终返回第一次 resolved 的结果。

    以下是只使用const来实现的方式:

    // NodeJs 方式的 async 单例
    // someAsyncOperationsToInitializeModule 为 async function
    // 注意,此处执行函数,未 await
    const someModule = someAsyncOperationsToInitializeModule()
    
    module.exports = someModule
    

    2 行代码,就够了。

    你该如何使用这个模块呢?

    // in async function
    // 不要用 "await getSomeModule()", 你不需要 `()`
    const getSomeModule = require('./getSomeModule')
    const someModule = await getSomeModule
    

    someModule 的值绝对与 [问题描述] 中提到的代码运行结果完全相同。

    你可能会注意到文件名最好更改为 ./someModule.js./asyncSomeModule.js .

    另外一个可能会提出的问题是,我们已经使用了 await getSomeModule() ,但是在当前方案中,被调整为了 await getSomeModule。如果我们采用这种解决方案,将会对现有代码造成很大的影响。

    其实,只需要做一点点调整,就可以保持之前的文件命名和调用方式。

    解决方案 B

    // NodeJS 方式的 async 单例
    
    const someModule = someAsyncOperationsToInitializeModule()
    
    module.exports = () => someModule
    

    现在,你无需改变任何外部代码。这种实现 100% 向后兼容。也就是说,你无需改造模块的调用方式,正如问题中所提到的调用方式一样。

    // in async function
    const getSomeModule = require('./getSomeModule')
    const someModule = await getSomeModule()
    

    Show me the Code

    https://repl.it/@victoratas/Singleton-in-Nodejs

    补充资料

    [1] https://nodejs.org/api/modules.html#modules_caching

    2 条回复    2020-08-02 11:36:34 +08:00
    jmyz0455
        1
    jmyz0455   361 天前
    感谢分享,不过老哥你这个主题我看着有点辛苦,背景是黑的,代码块大量文本是灰的,辨识度不高。这是您自己定义的主题吗?
    evilStart
        2
    evilStart   317 天前 via Android
    为什么不直接 module.exports = await someModule
    这样不就直接导出一个实例了么?
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1108 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 17ms · UTC 18:57 · PVG 02:57 · LAX 11:57 · JFK 14:57
    ♥ Do have faith in what you're doing.