为什么这个 EventEmitter pubsub 单例接口在 node.js 中不起作用?
Why isn't this EventEmitter pubsub singleton interface working in node.js?
我正在尝试将 node.js 中的发布者和订阅者分开,以便能够通过共享的 EventEmitter 实例作为总线相互发送数据。
我的总线遵循[此处][1]
讨论的单例方法
bus.js 文件
// https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/
// create a unique, global symbol name
// -----------------------------------
const FOO_KEY = Symbol.for("test.exchanges.bus");
const EventEmitter = require("events");
// check if the global object has this symbol
// add it if it does not have the symbol, yet
// ------------------------------------------
var globalSymbols = Object.getOwnPropertySymbols(global);
var hasFoo = (globalSymbols.indexOf(FOO_KEY) > -1);
if (!hasFoo){
global[FOO_KEY] = {
foo: new EventEmitter()
};
}
// define the singleton API
// ------------------------
var singleton = {};
Object.defineProperty(singleton, "instance", {
get: function(){
return global[FOO_KEY];
}
});
// ensure the API is never changed
// -------------------------------
Object.freeze(singleton);
// export the singleton API only
// -----------------------------
module.exports = singleton;
我的理解是,当我在不同的模块中需要这个文件时,应该提供相同的 foo 对象。这不就是单身的目的吗?
pub.js 文件
const bus = require("./bus");
class Publisher {
constructor(emitter) {
this.emitter = emitter;
console.log(this.emitter);
this.test();
}
test() {
setInterval(() => {
this.emitter.emit("test", Date.now());
}, 1000);
}
}
module.exports = Publisher;
console.log(bus.instance.foo);
sub.js 文件
const bus = require("./bus");
class Subscriber {
constructor(emitter) {
this.emitter = emitter;
console.log(this.emitter);
this.emitter.on("test", this.handleTest);
}
handleTest(data) {
console.log("handling test", data);
}
}
module.exports = Subscriber;
console.log(bus.instance.foo);
当我 运行 pub.js 和 sub.js 在 2 个单独的终端 windows 上时,sub.js 立即完成执行,就好像发布者没有将消息推送到它。谁能指出如何分离发布者和订阅者以使用相同的事件总线?
您可以考虑重新设计您的总线模块。我建议将其创建为扩展 EventEmitter
的 class,然后返回此 class.
的实例化实例
现在,当第一次加载此文件时,class 代码将 运行 并实例化一个对象,然后导出回来。 require
将缓存此实例,下次加载此文件时,它会取回相同的对象。这使它成为一个单例,您现在可以将其用作公共总线。
这里有一些代码可以证明这一点:
bus.js
const {EventEmitter} = require('events');
class Bus extends EventEmitter {
constructor(){
super();
setTimeout(() => this.emit('foo', (new Date()).getTime()), 1000);
}
}
module.exports = new Bus();
bus.spec.js
const bus1 = require('../src/util/bus');
const bus2 = require('../src/util/bus');
describe('bus', () => {
it('is the same object', () => {
expect(bus1).toEqual(bus2);
expect(bus1 === bus2).toEqual(true);
});
it('calls the event handler on bus2 when event is emitted on bus1', done => {
bus2.on('chocolate', flavor => {
expect(flavor).toBe('dark');
done()
});
bus1.emit('chocolate', 'dark');
}, 20)
});
我正在尝试将 node.js 中的发布者和订阅者分开,以便能够通过共享的 EventEmitter 实例作为总线相互发送数据。
我的总线遵循[此处][1]
讨论的单例方法bus.js 文件
// https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/
// create a unique, global symbol name
// -----------------------------------
const FOO_KEY = Symbol.for("test.exchanges.bus");
const EventEmitter = require("events");
// check if the global object has this symbol
// add it if it does not have the symbol, yet
// ------------------------------------------
var globalSymbols = Object.getOwnPropertySymbols(global);
var hasFoo = (globalSymbols.indexOf(FOO_KEY) > -1);
if (!hasFoo){
global[FOO_KEY] = {
foo: new EventEmitter()
};
}
// define the singleton API
// ------------------------
var singleton = {};
Object.defineProperty(singleton, "instance", {
get: function(){
return global[FOO_KEY];
}
});
// ensure the API is never changed
// -------------------------------
Object.freeze(singleton);
// export the singleton API only
// -----------------------------
module.exports = singleton;
我的理解是,当我在不同的模块中需要这个文件时,应该提供相同的 foo 对象。这不就是单身的目的吗?
pub.js 文件
const bus = require("./bus");
class Publisher {
constructor(emitter) {
this.emitter = emitter;
console.log(this.emitter);
this.test();
}
test() {
setInterval(() => {
this.emitter.emit("test", Date.now());
}, 1000);
}
}
module.exports = Publisher;
console.log(bus.instance.foo);
sub.js 文件
const bus = require("./bus");
class Subscriber {
constructor(emitter) {
this.emitter = emitter;
console.log(this.emitter);
this.emitter.on("test", this.handleTest);
}
handleTest(data) {
console.log("handling test", data);
}
}
module.exports = Subscriber;
console.log(bus.instance.foo);
当我 运行 pub.js 和 sub.js 在 2 个单独的终端 windows 上时,sub.js 立即完成执行,就好像发布者没有将消息推送到它。谁能指出如何分离发布者和订阅者以使用相同的事件总线?
您可以考虑重新设计您的总线模块。我建议将其创建为扩展 EventEmitter
的 class,然后返回此 class.
现在,当第一次加载此文件时,class 代码将 运行 并实例化一个对象,然后导出回来。 require
将缓存此实例,下次加载此文件时,它会取回相同的对象。这使它成为一个单例,您现在可以将其用作公共总线。
这里有一些代码可以证明这一点:
bus.js
const {EventEmitter} = require('events');
class Bus extends EventEmitter {
constructor(){
super();
setTimeout(() => this.emit('foo', (new Date()).getTime()), 1000);
}
}
module.exports = new Bus();
bus.spec.js
const bus1 = require('../src/util/bus');
const bus2 = require('../src/util/bus');
describe('bus', () => {
it('is the same object', () => {
expect(bus1).toEqual(bus2);
expect(bus1 === bus2).toEqual(true);
});
it('calls the event handler on bus2 when event is emitted on bus1', done => {
bus2.on('chocolate', flavor => {
expect(flavor).toBe('dark');
done()
});
bus1.emit('chocolate', 'dark');
}, 20)
});