javascript - 依赖 Node.js require 行为来实现单例是否安全?

标签 javascript node.js

假设我有一个这样实现的模块:

const dbLib = require('db-lib');
const dbConfig = require('db-config');

const dbInstance = dbLib.createInstance({
  host: dbConfig.host,
  database: dbConfig.database,
  user: dbConfig.user,
  password: dbConfig.password,
});

module.exports = dbInstance;

这里创建并导出了数据库连接池的实例。然后假设在整个应用程序中多次 require db-instance.js。 Node.js 应该只执行一次代码,并且始终传递同一个数据库池实例。依赖 Node.js require 命令的这种行为是否安全?我想使用它,这样我就不需要实现依赖注入(inject)。

最佳答案

Node.js 中所需的每个文件都是 Singleton。

此外 - require 是同步操作,并且它也确定性地工作。这意味着它是可预测的并且始终以相同的方式工作。

此行为不仅仅适用于 require - Node.js 在事件循环中只有一个线程,它的工作方式如下(稍作简化):

  • 看看有没有什么任务可以做
  • 接受任务
  • 从头到尾同步运行任务
  • 如果有任何异步调用,它只是将它们推送到“稍后执行”,但在任务的同步部分完成之前它永远不会启动它们(除非有工作线程生成,但您不需要知道有关此的详细信息)
  • 重复整个过程

例如,假设此代码是文件Infinite.js:

setTimeout(() => {
   while(true){
      console.log('only this');
   }
}, 1000)

setTimeout(() => {
   while(true){
      console.log('never this');
   }
}, 2000)

while(someConditionThatTakes5000Miliseconds){
   console.log('requiring');
}

当您需要此文件时,它首先注册到“doLater”,第一个 setTimeout 为“1000ms 后解析”,第二个 setTimeout 为“2000ms 后解析”(注意,它不是“1000ms 后运行”)。

然后它运行 while 循环 5000 毫秒(如果存在这样的条件),代码中不会发生任何其他事情。

5000ms 后,需求完成,同步部分完成,事件循环寻找新任务来执行。第一个看到的是延迟 1000 毫秒的 setTimeout(再一次 - 花了 1000 毫秒才标记为“可以由事件循环获取”,但你不知道它什么时候会运行)。

有永无休止的 while 循环,所以你会在控制台中看到“只有这个”。第二个 setTimeout 永远不会从 Event-Loop 中获取,因为它在 2000ms 后被标记为“可以获取”,但 Event Loop 已经陷入永无休止的 while 循环中。

有了这些知识,您就可以非常自信地使用 require (以及其他 Node.js 方面)。

结论 - require 是同步的、确定性的。一旦完成所需文件(它的输出是一个包含您导出的方法和属性的对象,如果您不导出任何内容,则为空对象),对此对象的引用将保存到 Node.js 核心内存中。当您从其他地方请求文件时,它首先查看核心内存,如果在那里找到需要的文件,它只会使用对该对象的引用,因此永远不会执行两次。


概念验证:

创建文件infinite.js

const time = Date.now();

setTimeout(() => {
    let i=0;
    console.log('Now I get stuck');
    while(true){
       i++;
       if (i % 100000000 === 0) {
           console.log(i);
       }
    }
    console.log('Never reach this');
 }, 1000)

 setTimeout(() => {
    while(true){
       console.log('never this');
    }
 }, 2000)

console.log('Prepare for 5sec wait')
while(new Date() < new Date(time + 5*1000)){
    // blocked
}
console.log('Done, lets allow other')

然后在同一文件夹中创建 server.js

console.log('start program');
require('./infinite');
console.log('done with requiring');

使用 Node 服务器运行它

这将是输出(数字永无止境):

start program
Prepare for 5sec wait
Done, lets allow other
done with requiring
Now I get stuck
100000000
200000000
300000000
400000000
500000000
600000000
700000000
800000000
900000000

关于javascript - 依赖 Node.js require 行为来实现单例是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49650124/

相关文章:

javascript - Protractor 应该看到 Chrome 的本地存储吗?

node.js - FIREBASE警告:用户回调引发了异常。 TypeError:req.next不是函数

node.js 和 express : use more than one views directory

javascript - 将前端 Javascript 与后端 Node.Js 和 mySQL 集成

node.js - Node 服务器在超过 1000 个项目的对象上崩溃

javascript - 根据屏幕尺寸的视口(viewport)值

javascript - 如何使用包含数组的 JSON 对象填充 ExtJS 组合框?

javascript - 在网络应用相机上叠加透明png

javascript - 在 Ember-CLI 的应用程序初始化程序中注入(inject)?

node.js - 使用可变数据渲染 HTML 并转换为 PDF