首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对于不同对象之间的交流,有比事件侦听更好的方法吗?

对于不同对象之间的交流,有比事件侦听更好的方法吗?
EN

Stack Overflow用户
提问于 2022-02-19 10:15:03
回答 1查看 129关注 0票数 2

假设我们有一个发射器对象实现某些逻辑,另一个不同类型的对象根据发射器对象触发的事件实现其他逻辑。我想,我们可以简单地通过在发射器中使用函数指针来解决这个问题,并通过使用一个函数来添加监听器对象的侦听器函数,比如下面的代码。甚至我们都能移除它。我可以说,就像DOM事件一样。

你能为这位来自其他行业的新手提供一个更好的方法吗?提前谢谢。

代码语言:javascript
运行
复制
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();
代码语言:javascript
运行
复制
.as-console-wrapper {
    max-height: 100% !important;
}

篡改上面的代码

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-19 10:55:56

事件

以这种方式使用事件是提供这种交流的一种很好的方式。如果您查找事件发射器(如Node.js )的现有实现,或者搜索“发布/订阅”,您将发现许多可以借鉴的现有技术。

一些注意事项:

  • 通常,您需要一组事件处理程序,而不是只允许一个事件处理程序。
  • 通常,发射器会在try/catch块中包装对事件处理程序的调用,以便抛出错误的处理程序不会阻止发射器代码继续执行其工作(通常只是通知侦听器事件)。
  • 有些系统(包括DOM)向所有侦听器提供相同的事件对象,允许它们之间进行一些交叉交谈。不加控制的相声可能是个坏主意,但某种形式的受控相声可能是有用的。
  • 类似地,一些系统(包括DOM)为事件侦听器提供了一种取消事件的方法,从而阻止它到达其他侦听器。

协同线

另一种在需要观察序列(在非常广泛的意义上)时,按照这些思路进行通信的方法是使用协同线。在JavaScript中,可以使用发电机实现协同,这是通过生成器函数最容易创建的。生成器是一个对象,它响应于对其next方法的调用而产生和使用值。

下面是一个非常简单的生成器,它只生成(不消耗)值:

代码语言:javascript
运行
复制
// 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`);
代码语言:javascript
运行
复制
.as-console-wrapper {
    max-height: 100% !important;
}

注意生成器的逻辑(在本例中是非常简单的逻辑,for循环)和它的使用者(同样非常简单,for-of循环)是如何混合的。

生成器是生成像这样的可迭代性的好方法,但它们也可以使用被推送给它们的值。要将值推送到生成器,直接调用next而不是隐式调用。下面是生成器的另一个简单示例,但是这个生成器同时生成和使用值--这是一个简单的1-100数字猜测游戏,生成器负责选择数字并告诉您猜值有多好:

代码语言:javascript
运行
复制
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();
代码语言:javascript
运行
复制
<p id="prompt"></p>
<input id="input" type="number" value="0" step="1">
<input id="button" type="button" value="Guess">

您可以看到使用它(doGuess)的代码与生成器的逻辑之间的交互。

Coroutines确实很有用,但是(IMHO)可能不像事件发射器那么普遍。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71183990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档