服务
服务是提供功能的长寿命代码。它们可以通过组件(使用useService)或其他服务导入。此外,它们还可以声明一组依赖项。从这个意义上讲,服务基本上是一个DI依赖注入系统。例如,通知服务提供了一种显示通知的方式,或者rpc服务是向Odoo服务器执行请求的正确方式。
以下示例注册一个简单的服务,该服务每5秒显示一次通知:
import { registry } from "@web/core/registry";
const myService = {
dependencies: ["notification"],
start(env, { notification }) {
let counter = 1;
setInterval(() => {
notification.add(`Tick Tock ${counter++}`);
}, 5000);
}
};
registry.category("services").add("myService", myService);
在启动时,web客户端启动服务注册表中存在的所有服务。请注意,注册表中使用的名称是服务的名称。
大多数不是组件的代码都应该打包在服务中,特别是当它产生一些副作用时。这对于测试非常有用:测试可以选择哪些服务是活动的,因此不必要的副作用干扰正在测试的代码的可能性较小。
定义服务
服务需要实现以下接口:
dependencies:
字符串的可选列表。它是此服务所需的所有依赖项(其他服务)的列表
start(env, deps)
参数
-
env (
Environment()
) – 应用程序环境 -
deps (
Object()
) – 所有请求的依赖项
返回:服务价值或承诺<服务价值>
这是服务的主要定义。它可以返回一个值或一个承诺。在这种情况下,服务加载程序只需等待promise解析为一个值,该值就是服务的值。
有些服务不出口任何价值。它们可能只是完成自己的工作,而不需要被其他代码直接调用。在这种情况下,它们的值将在env.services中设置为null。
async
可选值。如果给定,则应为true或字符串列表。
有些服务需要提供异步API。例如,rpc服务是一个异步函数,或者orm服务提供了一组函数来调用Odoo服务器。
在这种情况下,使用服务的组件可能会在异步函数调用结束之前被销毁。大多数情况下,需要忽略异步函数调用。否则可能非常危险,因为基础组件不再处于活动状态。async标志就是这样做的一种方式:它向服务创建者发出信号,如果组件被破坏,来自组件的所有异步调用都应该挂起
使用服务
依赖于其他服务并已正确声明其依赖关系的服务只需在start方法的第二个参数中接收对相应服务的引用。
useService挂钩是在组件中使用服务的正确方式。它只是返回一个对服务值的引用,然后组件可以稍后使用该引用。例如:
import { useService } from "@web/core/utils/hooks";
class MyComponent extends Component {
setup() {
const rpc = useService("rpc");
onWillStart(async () => {
this.someValue = await rpc(...);
});
}
}