diff --git a/src/plugins/data.ts b/src/plugins/data.ts index 9baa85a57..9f349fb0f 100644 --- a/src/plugins/data.ts +++ b/src/plugins/data.ts @@ -1,21 +1,44 @@ -// /** 数据注入 */ -// export interface PluginDataProvider { -// /** 执行数据注入, 参数将由插件注册者提供 */ -// insertData: (...args: any[]) => void | Promise -// } +/** + * 数据注入 API + * @module plugins/data + * + * 各个组件或插件可以通过该 API 进行数据通信。 + * 要进行通信,需要数据接收方准备一个或多个接受更改的对象给数据提供方。 + * 数据提供方通过修改这些对象本身来提供数据。双方通过一个唯一的 key 来标识数据。 + * + * 接收方通过 {@link registerData} 注册一个或多个接受更改的对象, + * 并通过 {@link getData} 获取被更改的对象。 + * 提供方通过 {@link addData} 提供 {@link PluginDataProvider} 来修改上述对象。 + * + * 数据接收方需要手动保证 `registerData` 在 `getData` 之前调用, + * 否则 `getData` 只会返回空数组。 + * + * `registerData` 只应被调用一次,多余的调用会被直接忽略。 + * + * `addData` 在 `registerData` 之前或之后调用都是允许的。 + * 不论是在之前还是在之后调用,其提供的 provider 都会被正确应用到已注册的或即将注册的数据上。 + * + * 提供方提供方提供的 provider 不会被立即应用,而是被存储起来,在 `getData` 时一次性应用。 + * 已经应用过的 provider 会被立刻丢弃,因此每个 provider 最多只会被执行一次。 + */ + /** 执行数据注入, 参数将由插件注册者提供 */ export type PluginDataProvider = (...args: any[]) => void | Promise const pluginDataMap = new Map() /** - * 注册数据, 允许其他代码向其中添加数据 - * @param key 标识ID - * @param data 提供的数据对象, 注入者将把数据添加到其中 + * 注册数据, 允许其他代码修改数据 + * @param key 数据的唯一标识 + * @param data 提供的一系列数据对象。会作为参数应用到每个 {@link PluginDataProvider} 上 */ export const registerData = (key: string, ...data: any[]) => { if (pluginDataMap.has(key)) { @@ -35,17 +58,19 @@ export const registerData = (key: string, ...data: any[]) => { }) } } + /** - * 向由`key`指定的对象注入数据 - * @param key 标识ID - * @param provider 数据注入的配置对象 + * 为 `key` 所标识的对象添加 provider + * @param key 数据的唯一标识 + * @param provider 用于修改数据的回调函数 */ export const addData = (key: string, provider: PluginDataProvider) => { if (pluginDataMap.has(key)) { - const { providers, registered, data } = pluginDataMap.get(key) - providers.push(provider) - if (registered) { + const { providers, loaded, data } = pluginDataMap.get(key) + if (loaded) { provider(...data) + } else { + providers.push(provider) } } else { pluginDataMap.set(key, { @@ -57,8 +82,9 @@ export const addData = (key: string, provider: PluginDataProvider) => { } } /** - * 从由`key`指定的对象获取数据, 未注册时返回空数组 - * @param key 标识ID + * 在注册的数据上应用未使用的 provider,并返回对象自身 + * @param key 数据的唯一标识 + * @returns 被更改后的数据。若数据尚未被注册,则返回空数组 */ export const getData = (key: string) => { if (pluginDataMap.has(key)) { @@ -69,6 +95,7 @@ export const getData = (key: string) => { if (registered) { if (!loaded) { providers.forEach(p => p(...data)) + item.providers = [] item.loaded = true } return data @@ -78,9 +105,10 @@ export const getData = (key: string) => { } /** - * 注册并获取数据 (`registerData`+`getData`) - * @param key 标识ID - * @param data 提供的数据对象, 注入者将把数据添加到其中 + * 注册并获取数据({@link registerData} + {@link getData}) + * @param key 数据的唯一标识 + * @param data 提供数据对象。将会应用到未使用的 provider + * @returns 被更改后的数据 */ export const registerAndGetData = (key: string, ...data: T) => { registerData(key, ...data)