使用observe 例程的想法似乎不错,但至少有几种方法可以实现。一种方法是延迟订阅本身。这是一个工作示例:
import { Meteor } from 'meteor/meteor';
import { TheCollection } from '/imports/collections.js';
Meteor.publish('delayed', function (delay) {
let isStopped = false;
const handle = TheCollection.find({}).observeChanges({
added: (id, fields) => {
Meteor.setTimeout(() => {
if (!isStopped) {
this.added(TheCollection._name, id, fields);
}
}, delay);
},
changed: (id, fields) => {
Meteor.setTimeout(() => {
if (!isStopped) {
this.changed(TheCollection._name, id, fields);
}
}, delay);
},
removed: (id) => {
Meteor.setTimeout(() => {
if (!isStopped) {
this.removed(TheCollection._name, id);
}
}, delay);
}
});
this.onStop(() => {
isStopped = true;
handle.stop();
});
this.ready();
});
另一种方法是创建一个仅用于渲染目的的本地ProxyCollection。数据将从TheCollection 复制到ProxyCollection,使用与订阅案例中相同的“观察技术”会有一些延迟。
在这两种情况下,您都需要处理一些极端情况,例如:
- 是否应该在初始加载时延迟数据?
- 如果文档被删除,是否应该延迟更新?
- 是否应该为初始化更改的用户延迟更新?
它们都可以通过利用和调整上述技术来解决。但我相信,它们不在这个问题的范围内。
编辑
为防止初始数据加载延迟,您可以按如下方式更新上述代码:
let initializing = true;
const handle = TheCollection.find({}).observeChanges({
added: (id, fields) => {
if (initializing) {
this.added(TheCollection._name, id, fields);
} else {
Meteor.setTimeout(() => {
if (!isStopped) {
this.added(TheCollection._name, id, fields);
}
}, delay);
}
},
// ...
});
// ...
this.ready();
initializing = false;
起初,它为什么会起作用可能并不明显,但这里的一切都是在纤程中执行的。 observeChanges 例程“阻塞”,它首先为整个初始数据集的每个文档调用 added。只有这样它才会进入您的发布方法主体的下一部分。
应该注意的是,由于上述行为,订阅可能会在初始数据集被处理之前停止,因此,甚至在定义 onStop 回调之前。在这种特殊情况下,它不应该受到伤害,但有时可能会出现问题。