通过阅读一些文字,尤其是iOS文档中关于委托的内容,所有的协议方法都被称为自定义委托对象需要实现的钩子。但是其他一些书,将这些钩子命名为回调,它们之间有什么区别?它们只是名称不同但机制相同吗?除了 Obj-C 之外,其他一些编程语言,比如 C 也中了钩,和 Obj-C 的情况一样吗?
4 回答
这里的术语有点模糊。一般来说,两者都试图达到相似的结果。
通常,回调是您向 API 注册的函数(或委托),以便在处理流程中的适当时间调用(例如,通知您处理处于某个阶段)
钩子传统上意味着更通用的东西,用于修改对 API 的调用(例如修改传递的参数,监视调用的函数)。在这个意义上,它通常比 Java 等高级语言所能达到的水平低得多。
在iOS的上下文中,钩子这个词的含义与上面的回调完全相同
让我加入一个 Javascript 答案。在 Javascript 中,回调、钩子和事件都被使用。按照这个顺序,它们都是比另一个更高层次的概念。
不幸的是,它们经常被不当使用,从而导致混乱。
回调
从控制流的角度来看,回调是一个函数,通常作为参数给出,您在从函数返回之前执行该函数。
这通常用于需要等待 I/O 的异步情况(例如 HTTP 请求、文件读取、数据库查询等)。您不想等待同步while
循环,因此可以同时执行其他功能。
当您获取数据时,您(永久)放弃控制并使用结果调用回调。
function myFunc(someArg, callback) {
// ...
callback(error, result);
}
因为回调函数可能是一些尚未执行的代码,并且您不知道调用堆栈中函数上方的内容,所以通常不是抛出错误,而是将错误作为参数传递给回调。有错误优先和结果优先的回调约定。
在 Javascript 世界中,大多数回调已被Promises取代,并且从 ES2017+ 开始,您可以本机使用async/await
来摆脱富含回调的意大利面条式代码,并使异步控制流看起来像是同步的。
有时,在特殊的级联控制流中,您在函数中间运行回调。例如,在您运行的Koa(Web 服务器)中间件或Redux 中间件next()
中,它会在堆栈中的所有其他中间件都运行后返回。
挂钩
钩子并不是一个定义明确的术语,但在 Javascript 实践中,当您希望客户端(API/库用户、子类等)在控制流中定义明确的点采取可选操作时,您可以提供钩子。
因此,钩子可能是您在某个时间点调用的某个函数(例如,作为参数或类方法),例如在数据库更新期间:
data = beforeUpdate(data);
// ...update
afterUpdate(result);
通常的重点是:
- 挂钩可以是可选的
- 钩子通常是等待的,即它们在那里修改一些数据
- 每个钩子最多调用一个函数(与事件相反)
React 在其Hooks API中使用了钩子,它们——引用它们的定义——“是让你“钩入”React 状态和生命周期特性的函数”,即它们让你改变 React 状态,并且每次在某些情况下运行自定义函数部分状态发生变化。
活动
在 Javascript 中,事件在特定时间点发出,客户端可以订阅它们。事件发生时调用的函数称为侦听器- 或者为了增加混淆,回调。我更喜欢避免使用“回调”这个词,而是使用“监听器”这个词。
这也是一种通用的 OOP 模式。
在前端有一个用于事件的DOM 接口,在 node.js 中有EventEmitter接口。在ReactiveX中实现了一个复杂的异步版本。
事件的属性:
- 可能有多个侦听器/回调订阅(将执行)同一事件。
- 它们通常不接收回调,只接收一些事件信息并同步运行
- 通常,与 hooks 不同的是,它们不用于修改事件发射器控制流中的数据。发射器不在乎“是否有人在听”。它只是使用事件数据调用侦听器,然后立即继续。
示例:当数据流开始或结束、用户单击按钮或修改输入字段时发生事件。
这两个术语非常相似,有时可以互换使用。钩子是库中的一个选项,用户代码可以链接一个函数来改变库的行为。库函数不需要与用户代码同时运行;就像在析构函数中一样。
回调是一种特定类型的钩子,用户代码将在其中启动库调用,通常是 I/O 调用或 GUI 调用,它将控制权交给内核或 GUI 子系统。然后,控制进程在中断或信号上“回调”用户代码,以便用户代码可以提供处理程序。
从历史上看,我见过用于中断处理程序的钩子和用于 GUI 事件处理程序的回调。我还看到当例程是静态链接和动态代码中使用回调时使用的钩子。
已经有两个很好的答案,但我想再提供一个证据,术语“钩子”和“回调”是相同的,并且可以互换使用:FreeRTOS 支持“钩子”一词,但将“回调”视为等价词术语,当他们说:
空闲任务可以选择调用应用程序定义的挂钩(或回调)函数 - 空闲挂钩。
滴答中断可以选择调用应用程序定义的挂钩(或回调)函数 - 滴答挂钩。
由 heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c 实现的内存分配方案可以选择包含一个 malloc() 失败挂钩(或回调)函数,该函数可以配置为在 pvPortMalloc() 时调用永远返回 NULL。