假设我们有一个发射器对象实现某些逻辑,另一个不同类型的对象根据发射器对象触发的事件实现其他逻辑。我想,我们可以简单地通过在发射器中使用函数指针来解决这个问题,并通过使用一个函数来添加监听器对象的侦听器函数,比如下面的代码。甚至我们都能移除它。我可以说,就像DOM事件一样。
你能为这位来自其他行业的新手提供一个更好的方法吗?提前谢谢。
class Emitter {
constructor() {
this.event1 = this.empty;
this.event2 = this.empty;
}
empty(){}
someEmmitterLogic(input) {
// arbitrary logic here before event1 occurs
this.event1({message:"produced at event1", b:1});
// maybe event2 can also occur here
this.event2({message:"produced at event2", d:2});
}
addEvent(event, listener) {
switch (event) {
case "event1":
this.event1 = listener;
break;
case "event2":
this.event2 = listener;
break;
default:
console.log("Sorry, we don't emit this event.");
}
}
removeEvent(event) {
switch (event) {
case "event1":
this.event1 = this.empty;
break;
case "event2":
this.event2 = this.empty;
break;
default:
console.log("Sorry, cannot remove an event we are not emitting.");
}
}
}
class Listener{
constructor(){
// Simple listeners outputting the event object to the console
this.listener1 = (e) => console.log(e.message);
this.listener2 = (e) => console.log(e.message);
}
}
///////////////////////////////////////////////////////////////////////////
const emitter = new Emitter();
const listener = new Listener();
console.log("STATUS: not listening emitter");
emitter.someEmmitterLogic();
// Add listeners
emitter.addEvent("event1", listener.listener1);
emitter.addEvent("event2", listener.listener2);
console.log("STATUS: started listening emitter");
emitter.someEmmitterLogic();
console.log("say we don't need event1 anymore, let's remove it");
emitter.removeEvent("event1");
console.log("STATUS: listening event2 only");
emitter.someEmmitterLogic();
.as-console-wrapper {
max-height: 100% !important;
}
发布于 2022-02-19 10:55:56
事件
以这种方式使用事件是提供这种交流的一种很好的方式。如果您查找事件发射器(如Node.js )的现有实现,或者搜索“发布/订阅”,您将发现许多可以借鉴的现有技术。
一些注意事项:
try
/catch
块中包装对事件处理程序的调用,以便抛出错误的处理程序不会阻止发射器代码继续执行其工作(通常只是通知侦听器事件)。协同线
另一种在需要观察序列(在非常广泛的意义上)时,按照这些思路进行通信的方法是使用协同线。在JavaScript中,可以使用发电机实现协同,这是通过生成器函数最容易创建的。生成器是一个对象,它响应于对其next
方法的调用而产生和使用值。
下面是一个非常简单的生成器,它只生成(不消耗)值:
// Generator function (note the `*` after `function`) returns
// a generator. This generator provides a series of values in
// a given range (inclusive).
function* range(from = 1, to = 10) {
console.log("Generator: Starting");
for (let value = from; value <= to; ++value) {
console.log(`Generator: Ready with value ${value}`);
yield value;
}
}
// A popular way to consume generators (and iterables in general) is
// the `for-of` loop. When the generator/iterable is infinite
// as in our case, you need to be sure to break out of it at some point.
for (const value of range(1, 5)) {
console.log(`for-of: Received ${value}`);
}
console.log(`Done`);
.as-console-wrapper {
max-height: 100% !important;
}
注意生成器的逻辑(在本例中是非常简单的逻辑,for
循环)和它的使用者(同样非常简单,for-of
循环)是如何混合的。
生成器是生成像这样的可迭代性的好方法,但它们也可以使用被推送给它们的值。要将值推送到生成器,直接调用next
而不是隐式调用。下面是生成器的另一个简单示例,但是这个生成器同时生成和使用值--这是一个简单的1-100数字猜测游戏,生成器负责选择数字并告诉您猜值有多好:
function* hiddenNumber(from = 1, to = 100) {
console.log("Generator: Starting");
const size = (to - from + 1);
const num = Math.floor(Math.random() * size) + from;
// console.log("cheat: " + num);
let guess = yield `Pick a number between ${from} and ${to} (inclusive)`;
while (guess !== num) {
if (guess < num) {
if (Math.abs(num - guess) >= size / 2) {
guess = yield "REALLY low";
} else {
guess = yield "too low";
}
} else if (guess > num) {
if (Math.abs(num - guess) >= size / 2) {
guess = yield "REALLY high";
} else {
guess = yield "too high";
}
}
}
return "you got it!";
}
const prompt = document.getElementById("prompt");
const input = document.getElementById("input");
const button = document.getElementById("button");
const doGuess = () => {
const num = input.valueAsNumber;
const result = game.next(num);
const answer = result.value;
prompt.textContent = answer;
if (result.done) {
button.disabled = true;
} else {
input.focus();
input.select();
}
};
const game = hiddenNumber();
prompt.textContent = game.next().value;
button.addEventListener("click", doGuess);
input.addEventListener("keypress", event => {
if (event.key === "Enter") {
doGuess();
}
});
input.select();
<p id="prompt"></p>
<input id="input" type="number" value="0" step="1">
<input id="button" type="button" value="Guess">
您可以看到使用它(doGuess
)的代码与生成器的逻辑之间的交互。
Coroutines确实很有用,但是(IMHO)可能不像事件发射器那么普遍。
https://stackoverflow.com/questions/71183990
复制相似问题