V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
rizon
V2EX  ›  程序员

nodejs 的单例模式问题

  •  
  •   rizon ·
    othorizon · 19 小时 25 分钟前 via Android · 1283 次点击

    想问一下在 nodejs 或 nextjs 里。 prisma mongodb redis lrucache 等等这些需不要做单例模式的处理呢? 哪些做哪些不做? 用 declar global 还是 class 做?

    为啥我 lrucache 不用 global 做单例一部署生产就存在缓存删除不掉的问题( class 写单例也不行)开发环境就没事

    13 条回复    2024-12-18 17:27:10 +08:00
    zy445566
        1
    zy445566  
       19 小时 12 分钟前
    不需要 new 的,基本就不用做单例,模块引用有缓存,其实也相当于了单例
    单例一般也不挂全局吧,我觉得把单例 export 出去就好,只要有引用就存活
    缓存删除不了,最好把最简化代码和对应的文件名列一下,光一句话基本没法判断问题
    sch1111878
        2
    sch1111878  
       19 小时 10 分钟前
    好问题

    看 prisma 的官方文档里是推荐的 declare global 的, 而且只需开发环境这样做,
    rizon
        4
    rizon  
    OP
       18 小时 39 分钟前 via Android
    @sch1111878 这是为了避免开发环境的热加载带来的问题。但我想的是代码写都写了,为什么还要专门只针对开发生效,我上线生产环境也没什么坏处吧
    sch1111878
        5
    sch1111878  
       18 小时 32 分钟前
    @rizon 是这个道理
    zy445566
        6
    zy445566  
       17 小时 57 分钟前
    @sch1111878 #3 所以需要 new 的,那可以加个单例
    zhuisui
        7
    zhuisui  
       17 小时 32 分钟前
    单例是 nodejs 运行时的对象实例分配的事情,库的功能还要结合对应的中间件或者服务考虑,不能一概而论,这个得结合对应的库的功能实现来考虑。
    举个例子,prisma+底层数据库,底层调用有连接池,此时用单例也不会影响并发调用;而 ioredis 单实例的调用内部是单连接,调用 subscribe 或者 block 调用就会阻塞其他调用。
    另外,复杂的框架还要针对各种库进行封装,以适应不用的业务需要。
    sch1111878
        8
    sch1111878  
       17 小时 7 分钟前
    @zy445566 不好意思 你那句话我断句错误了, 理解错了
    rizon
        9
    rizon  
    OP
       16 小时 26 分钟前 via Android
    @zhuisui 还真是!!!也就是如果 ioredis 我用了单例 会阻塞调用??
    但是我在 export 出去的时候,一个模块不也会被缓存吗,实际上我不额外写单例,nodejs 也只会创建一个实例吧?
    所以 ioredis 内部是不是做了什么分时优化之类的东西
    rizon
        10
    rizon  
    OP
       16 小时 17 分钟前
    @zhuisui #7
    const Redis = require("ioredis");
    const redis = new Redis();

    // Create a shared Redis instance for the entire application.
    // Redis is single-thread so you don't need to create multiple instances
    // or use a connection pool.
    module.exports = redis;
    这是 ioredis 官方的 express 案例里的。所以说我创建单实例或者不创建单实例,实际上应该是一样的吧。但是为了代码的可读性和可维护性,我是不是创建单实例更省心一些
    zhuisui
        11
    zhuisui  
       11 小时 47 分钟前
    关于 ioredis 的阻塞调用,你可以看 https://github.com/redis/ioredis?tab=readme-ov-file#pubsub ,这是 pub sub 相关的。
    你上面贴的 redis 代码里几句注释里的 single-thread 是 redis 程序自身的,不是指 node 的。而且这段只适用于普通的非阻塞调用命令。
    总之,实例、连接、线程、调用,这是四种概念,还要分开是 node 进程的还是 redis 进程的,不能一概而论。
    最后,具体情况具体分析。
    zhuisui
        12
    zhuisui  
       11 小时 44 分钟前
    你通过代码写单例,和 node 包管理机制导致的单例,那也是两码事。
    对于后者的 commonjs ,清除 require cache 重新 require 就会创建一个新实例,旧的还会存在。
    Plumbiu
        13
    Plumbiu  
       10 小时 50 分钟前
    next.js 服务端有两个运行时 https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes ,单例其实很容易出错...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1003 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 20:17 · PVG 04:17 · LAX 12:17 · JFK 15:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.