为什么使用事件监听器而不是函数调用?

发布于 2024-10-09 00:00:44 字数 319 浏览 0 评论 0原文

我最近一直在研究事件监听器,我想我终于把它们搞定了。基本上,它们是在另一个对象的方法上调用的函数。我的问题是,为什么在调用函数时创建事件监听器就可以正常工作?

例如,我想调用player.display_health(),当它被触发时,应该触发并存储方法player.get_health(),以便display_health()可以访问它。为什么我应该使用事件侦听器而不是简单地调用函数?即使 display_health() 在另一个对象中,这对我来说仍然不是问题。

如果您有另一个更适合用法的示例,请告诉我。也许特定语言并没有从中受益那么多? (Javascript、PHP、ASP?)

I've been studying event listeners lately and I think I've finally gotten them down. Basically, they are functions that are called on another object's method. My question is, why create an event listener when calling the function will work just fine?

Example, I want to call player.display_health(), and when this is fired, the method player.get_health() should be fired and stored so that display_health() has access to it. Why should I use an event listener over simply calling the function? Even if display_health() were in another object, this still doesn't appear to be a problem to me.

If you have another example that fits the usage better, please let me know. Perhaps particular languages don't benefit from it as much? (Javascript, PHP, ASP?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橘和柠 2024-10-16 00:00:44

您可能并不总是能够控制执行调用的代码。或者即使是,您也不想在该代码中引入依赖项。在这种情况下,最好让代码触发事件并允许您控制的代码或应该具有依赖项的代码侦听该事件并采取相应的操作。

例如,也许您正在创建一个可供其他人使用的库。他们没有源代码,或者在某种程度上不能/不应该修改它(或者不应该)。您的文档指出特定事件是在特定情况下引发的。然后他们可以依次对这些事件做出反应。

或者您的企业中可能有一些域库。您确实可以控制它们并可以修改它们,但从架构上来说,它们通常被认为是按当前编码方式工作的,不应更改。 (不想进行一轮质量检查来重新验证更新的代码,该代码属于另一个部门,他们不希望您更改它,等等)并且您处于您想要的位置代码能够在不同的情况/环境下做不同的事情。如果该代码引发相关事件,您可以将代码挂入其中(和/或相应地换出),而不必弄乱该代码。

只是几个简单的例子,我相信其他人还有更多。

You might not always be in control of the code that's doing the calling. Or even if you are, you don't want to introduce dependencies into that code. In cases like that, it's better for the code to fire an event and allow the code you do control, or the code that should have the dependency, to listen for the event and act accordingly.

For example, perhaps you're creating a library that will be used by other people. They don't have the source code or in some way can't/shouldn't be able to modify it (or shouldn't have to). Your documentation states that specific events are raised under specific circumstances. They can then, in turn, respond to those events.

Or perhaps you have some domain libraries in your enterprise. You do control them and can modify them, but architecturally they're generally considered to be working as they currently are coded and shouldn't be changed. (Don't want to incur a round of QA to re-validate the updated code, the code belongs to another department and they don't want you to change it, etc.) And you're in the position where you want that code to be able to do different things in different circumstances/environments. If that code raises and event where relevant, you can hook your code into it (and/or swap out accordingly) without having to mess with that code.

Just a couple quick examples, I'm sure others have more.

浅忆流年 2024-10-16 00:00:44

我的问题是,为什么在调用函数时创建一个事件监听器就可以正常工作?

如果您不知道要调用什么函数怎么办?

举一个经典的例子,用户可以点击的按钮。编写该库的人不知道单击按钮时要调用什么函数。如果每个 Button 在单击时只能调用相同的函数,那也是相当令人望而却步的。

因此,您可以将事件处理程序附加到该事件。然后,当事件被触发时,按钮可以执行它需要的操作,而不必在编译时确切地知道它应该调用哪个函数。

My question is, why create an event listener when calling the function will work just fine?

What if you don't know what function you want to call?

Take the classic example, a Button that the user can click on. Whoever writes the library has no idea what function you want called when the button is clicked. It would also be pretty prohibitive if every Button could only call the same function when it is clicked.

So instead, you can attach an event handler to the event. Then when the event is triggered, the Button can do what it needs to, without having to know at compile-time exactly what function it's supposed to be calling.

今天小雨转甜 2024-10-16 00:00:44

即使有了上面的详细答案,我仍然无法理解使用控制器/函数或事件侦听器之间的实际区别。

所有这些答案中遗漏的一件事是,当您不想如此紧密地耦合代码时,事件和事件侦听器的使用会派上用场。每个函数、类等都应该有单一的目的。

假设您收到了来自外部人员的 API 请求。就我而言,我理解这个概念的确切问题是当我从 Stripe Webhooks 接收 API 调用时。

Stripe Webhooks 的目的是:假设客户在您的网站上花费了 10,000 美元。您的标准程序是验证和捕获。更新数据库以反映他们的新会员身份。在完美的世界中,就我们公司而言,999/1000 次,这一切都很完美。他们的卡要么当场被拒绝,要么付款成功。在这两种情况下,我们都会向他们发送一封电子邮件,让他们知道。

但是,当用户付款并且 Stripe 返回卡故障错误(可能是多种不同的情况)时,有 1/1000 的情况会怎样呢?就我们而言,我们会向他们发送电子邮件并告诉他们计费失败。我们遇到的问题是,一些银行正在调查大笔费用,结果返回错误,但几分钟后银行批准了费用并捕获了付款。

那么有什么办法呢?输入 Stripe Webhooks。如果发生类似情况,Stripe Webhooks 将命中 API 端点。实际上,每当付款未立即经过验证、捕获或客户要求退款时,Stripe Webhooks 都可以随时访问您的 API。

这就是事件监听器派上用场的地方。 Stripe 通过 POST 发送客户信息以及 Webhook 类型。我们现在将处理该问题,更新数据库,并向他们发送成功电子邮件。

但是为什么不直接使用标准路由和控制器呢?
我们不只使用标准路由和控制器的原因是因为我们要么需要修改已经定义的函数、类等,要么创建一系列耦合在一起的新类,例如 ->收到 Stripe API 调用、更新数据库、发送电子邮件。我们没有将它们紧密耦合在一起,而是使用事件监听器首先接受 API 调用,然后调用每个类、函数等,使所有内容都解耦。

我到处查看,我认为 Laravel 文档解释得最好。当给出一个具体的例子时,我终于明白了事件监听器的目的是什么:

事件是解耦应用程序各个方面的好方法,因为单个事件可以有多个彼此不依赖的侦听器。例如,您可能希望在每次订单发货时向您的用户发送一条 Slack 通知。您可以引发 OrderShipped 事件,侦听器可以接收该事件并将其转换为 Slack 通知,而不是将订单处理代码耦合到 Slack 通知代码。

https://laravel.com/docs/5.6/events

Even with the detailed answers above, I was still having trouble understanding what the actual difference was between using a controller / functions OR an event listener.

One of the things that has been left out in all of these answers is that the use of Events and Event Listeners comes in handy when you do not want to couple your code so closely. Each function, class, etc, should have singleness of purpose.

So say you are getting hit with an API request from an outsider. In my case, my exact problem understanding this concept was when I am receiving API calls from Stripe Webhooks.

The purpose of Stripe Webhooks is: say a customer spends $10,000 on your website. Your standard procedure is to Auth and Capture. Update DB to reflect their new membership status. In a perfect world, and in our company's case, 999/1000 times, this goes perfectly. Either their card is declined on the spot, or the payment goes through. In both cases, we send them an email letting them know.

But what about the 1/1000 time when the user pays and Stripe returns a Card Failure error (which can be a number of different things)? In our case, we email them and tell them the billing has failed. The problem we've encountered is that some BANKS are investigating large charges, which comes back as an Error, but then a few minutes later the bank authorizes the charges and the payment is captured.

So what is there to do? Enter Stripe Webhooks. Stripe Webhooks will hit an API endpoint if something like this occurs. Actually, Stripe Webhooks can hit your API any and every time a payment isn't instantly Authed, Captured, or if the customer asks for a refund.

This is where an Event Listener comes in handy. Stripe shoots over a POST with the customer info, as well as the Webhook type. We will now process that, update the database, and shoot them a success email.

But why not just use a standard route and controller?
The reason we don't just use a standard route and controller is because we would either need to modify the already defined functions, classes, etc, or create a new series of classes that are coupled together, such as -> Stripe API Calls Received, Update DB, Send Email. Instead of coupling these closely together, we use an Event Listener to first accept the API Call, then hit each of those Classes, Functions, etc., leaving everything uncoupled.

I looked everywhere, and I think the Laravel documentation explains it best. I finally understood when given a concrete example, and what the purpose of an Event Listener is:

Events serve as a great way to decouple various aspects of your application, since a single event can have multiple listeners that do not depend on each other. For example, you may wish to send a Slack notification to your user each time an order has shipped. Instead of coupling your order processing code to your Slack notification code, you can raise an OrderShipped event, which a listener can receive and transform into a Slack notification.

https://laravel.com/docs/5.6/events

风流物 2024-10-16 00:00:44

简而言之,您可以编写没有事件侦听器的代码,但使用事件侦听器可以帮助其他人使用与库相同的代码。

In Brief, you can write the code without event listener, but using event listener help other to use the same code as library.

小姐丶请自重 2024-10-16 00:00:44

我认为事件与函数调用的主要原因是事件是“监听”,而调用是“进行”。因此,函数调用总是对另一个对象进行,而侦听器“选择”侦听从对象广播的事件。
观察者模式是对这种能力的一个很好的研究。这是一个简短的 node.js 示例,它说明了这个概念:

var events = require('events');
var Person = function(pname) {
    var name = pname;
};


var james = new Person('james');
var mary = new Person('mary');
var loudmouth = new Person('blabberer');

loudmouth.mouth = new events.EventEmitter();

//jame's observer.
james.read_lips = function(msg){
    console.log("james found out: " + msg);
};

//james adds his event to the emitter's event listener.
james.enter_elevator = function(){
    console.log('james is in the elevator');
    //NOTE: james adds HIMSELF as a listener for the events that may
    //transpire while he is in the elevator.
    loudmouth.mouth.on('elevator gossip', james.read_lips)
};

//james removes his event from the emitter when he leaves the elevator.
james.leave_elevator = function(){
    // read lips is how james responds to the event.
    loudmouth.mouth.removeListener('elevator gossip', james.read_lips);
    console.log('james has left the elevator');
};

//mary's observer
mary.overhear = function(msg){
    console.log("mary heard: " + msg);
};

//mary adds her observer event to the emitter's event listeners
mary.enter_elevator = function(){
    // overhear is how mary responds to the event.
    console.log('mary is in the elevator');
    //NOTE: now mary adds HERSELF to the listeners in the elevator and 
    //she observes using a different method than james which suits her.
    loudmouth.mouth.on('elevator gossip', mary.overhear);
};

loudmouth.speaks = function(what_is_said){
    console.log('loudmouth: ' + what_is_said);
    this.mouth.emit('elevator gossip', what_is_said);
};

james.enter_elevator();
mary.enter_elevator();
loudmouth.speaks('boss is having an affair');
james.leave_elevator();
loudmouth.speaks('just kidding');
console.log('james did not hear the last line because he was not listening anymore =)');

因此在这个“故事”中,参与者选择监听或何时不监听来自第三方的事件。我希望这有帮助。

I think the main reason for events vs function calls is that events are 'listened to' while calls are 'made'. So a function call is always made to another object whereas listeners 'choose' to listen for an event to be broadcast from your object.
The observer pattern is a good study for this capability. Here is a brief node.js example which illustrates the concept:

var events = require('events');
var Person = function(pname) {
    var name = pname;
};


var james = new Person('james');
var mary = new Person('mary');
var loudmouth = new Person('blabberer');

loudmouth.mouth = new events.EventEmitter();

//jame's observer.
james.read_lips = function(msg){
    console.log("james found out: " + msg);
};

//james adds his event to the emitter's event listener.
james.enter_elevator = function(){
    console.log('james is in the elevator');
    //NOTE: james adds HIMSELF as a listener for the events that may
    //transpire while he is in the elevator.
    loudmouth.mouth.on('elevator gossip', james.read_lips)
};

//james removes his event from the emitter when he leaves the elevator.
james.leave_elevator = function(){
    // read lips is how james responds to the event.
    loudmouth.mouth.removeListener('elevator gossip', james.read_lips);
    console.log('james has left the elevator');
};

//mary's observer
mary.overhear = function(msg){
    console.log("mary heard: " + msg);
};

//mary adds her observer event to the emitter's event listeners
mary.enter_elevator = function(){
    // overhear is how mary responds to the event.
    console.log('mary is in the elevator');
    //NOTE: now mary adds HERSELF to the listeners in the elevator and 
    //she observes using a different method than james which suits her.
    loudmouth.mouth.on('elevator gossip', mary.overhear);
};

loudmouth.speaks = function(what_is_said){
    console.log('loudmouth: ' + what_is_said);
    this.mouth.emit('elevator gossip', what_is_said);
};

james.enter_elevator();
mary.enter_elevator();
loudmouth.speaks('boss is having an affair');
james.leave_elevator();
loudmouth.speaks('just kidding');
console.log('james did not hear the last line because he was not listening anymore =)');

so in this 'story' the actors choose to listen or when to not listen for events from a third party. I hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文