【发布时间】:2010-01-15 05:57:09
【问题描述】:
事件处理程序和回调函数有什么区别?
【问题讨论】:
标签: architecture callback event-handling language-agnostic
事件处理程序和回调函数有什么区别?
【问题讨论】:
标签: architecture callback event-handling language-agnostic
回调是作为参数传递给另一个过程的过程。接收参数的过程可以调用它,或者共享它以便系统中的一些其他过程可以调用它。
事件处理程序是在事件发生时调用的过程。可以是回调。
【讨论】:
一般来说,“回调”是在检测过程的控制之下。
因此,您告诉 GUI 管理器“按下此按钮时调用 myaction”,然后 GUI 管理器会在按下按钮时调用该操作。
另一方面,事件处理程序在一个步骤中运行。 GUI 管理器被配置为向事件处理程序发送消息。您告诉事件管理器按钮按下由myaction 程序处理。当按下按钮时,GUI 管理器将消息放在事件处理程序的队列中并继续进行 GUI 管理。事件处理程序从队列中获取消息,看到它是一个按钮按下,启动myaction 程序,然后继续处理下一个事件。通常myaction程序会作为独立线程甚至独立进程运行。
虽然“事件处理程序”模式更复杂,但它更加健壮,并且在操作失败时挂起的可能性更小。它还提供了响应更快的 GUI。
【讨论】:
事件处理程序是一种回调。每当发生事件时都会调用它。该术语通常用于用户界面,其中事件是诸如移动鼠标、单击某物等。
【讨论】:
事件 - 想想服务器(员工)和客户端(老板)。一个员工可以有多个老板。员工发起事件,当他完成任务时,老板可以决定是否监听员工事件。员工是发布者,老板是订阅者。
回调 - 老板特别要求员工执行一项任务,在任务完成时,老板希望得到通知。员工将确保当任务完成后,他只通知请求的老板,而不是所有老板。如果部分工作完成,员工不会通知老板。完成所有任务后才会有。只有一位老板要求信息,员工只回复一位老板。
【讨论】:
回调(来自维基百科):“作为参数传递给其他代码的可执行代码”。
事件处理程序(再次来自维基百科):“异步处理程序中接收到的输入的回调子程序”。
这恰好是我一直以来的理解方式:事件处理程序是一种非常特殊的回调类型。
【讨论】:
这个问题很老了,但我发现MSDN 的这个链接很有趣。我希望任何偶然发现这个问题的人都能从这个链接中得到一些东西。
【讨论】:
另一方面,事件描述了过去发生的事情,而回调通常在事情发生时使用。
当事件触发时,您会被告知发生了什么事。使用回调时,系统会要求您参与某些事情。
库或框架可能会发出事件,让您知道发生了什么事。框架为您提供了可以插入代码(可能作为回调)的点,以便您可以积极参与流程。
部分问题在于事件、回调指的是技术机制以及更抽象的过程。
【讨论】:
底层机制相似,但语义不同。回调和事件处理程序都被异步调用。
回调函数通常从调用例程显式传递以请求某些信息。信息在一段时间后返回,由被调用者作为参数传递回回调。此时,调用例程完成其业务。通常回调是一个闭包 - 在调用例程中的语法上,并且通常是未命名的(匿名的)。它可能看起来有点像下面的,在 javascript 中:
function caller() {
someLibrary.getMeSomething(arg1, arg2, function(returnedData) {
// this is the callback which will do something with returnedData
});
}
所以被调用者(someLibrary.getMeSomething)被赋予了一个匿名回调函数,一段时间后这个函数被调用返回数据。回调就像对单个接收器的单次事件。
事件处理程序也被“回调”,但通常它们会在较长时间内用于多个事件,例如鼠标点击、网络事件等。此外,多个对象可能对同一事件感兴趣。由于这些原因,您通常“订阅”或“注册”设置代码中的事件(如对象初始化),并且事件处理程序更典型的是命名方法。通常,每个事件类型也被标识为常量或字符串。
所以在 Python 中它可能看起来像:
class MyUIClass:
def __init__(self):
someUILib.register(someUILib.events.MOUSE_CLICK, self.my_mouse_click_handler);
def my_mouse_click_handler(self, eventInfo):
# do something with event
if eventInfo.x < 100:
print 'You clicked in the margin'
【讨论】:
回调是作为参数传递给另一个函数(方法)的函数(方法)。接收参数的函数(方法)可以调用它,或者共享它以便系统中的其他函数(方法)可以调用它。
事件处理程序是在事件发生时调用的函数(方法)。可以是回调。
【讨论】:
事件处理程序也是一个回调。它只是更加解耦。
传统上,进程“A”会将指向其中一个方法(回调)的指针传递给外部进程“B”,以便 B 稍后可以根据实现的逻辑调用它。
例如假设我们的目标是检查 API 调用是否成功。
如果成功,我们将值“成功”存储在变量中,如果没有,则将“失败”存储在其中。这个变量由我们的程序“P”中的一个函数“checkIfAPICallSucceded”更新,它接受 API 响应作为参数来决定这个变量的命运。
以下是普通回调场景的实现方式:
这里的问题是 Q 对 P(P 中回调的内存地址)“了解太多”。这可能并不理想。
在事件处理程序中,不同之处在于回调本身永远不会传递给 Q。相反,在收到响应时,Q 只是宣布一个事件(包含响应的状态和数据的对象)。另一个称为事件循环“EL”的程序(这是一个侦听事件的简单程序)管理回调的执行。
这样 Q 永远不会知道 P 的任何事情。事实上 Q 甚至可能不会直接将 e 推送到事件队列中,操作系统可能会代表它执行此操作,在这种情况下 Q 甚至不知道 EL。
使用事件循环来处理回调会带来以下好处:
因此,事件处理程序模型需要额外的程序 (EL),因此需要额外的资源(CPU 时间和内存)。它最适合 I/O 操作,几乎可以肯定这些程序是由完全不同的团队开发的(因此信任级别低)
Q “知道” P 的简单回调可能听起来令人不快,但是当创建 Q 和 P 的同一团队(高信任度)时,简单的回调可以节省资源。
【讨论】:
在最高抽象级别上,事件回调和处理程序是相同的,即您有一个事件和对该事件的响应。 (响应只是一段代码,需要运行以响应发生的事情。)两者之间的区别在于,如果直接或间接调用此代码。在回调的情况下,直接调用代码,即回调本身。在事件处理程序的情况下,首先将此事件传达或通知给正确的接收者,然后再调用代码。
【讨论】:
事件具有冒泡等特殊功能。如果您不需要这些功能,则只需使用回调即可。
【讨论】:
回调是要求另一个函数进行业务操作并发送结果,而事件不是要求移交控制权,以便我们只能处理业务操作。
例如:按钮点击是事件(我们在点击按钮时进行业务操作)。由于forEach方法在进行业务操作并提供结果,所以在回调中循环集合。
【讨论】:
事件处理程序是来自系统的回调。
【讨论】: