假设我有一个这样实现的模块:
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/