angular - 重复定时动作的正确设计
问题描述
语境
- 角度:6.1.0
- NgRx:6.0.1
- RxJS:6.0.0
我正在创建一个页面,您可以在给定时间设置一些警报,并且它们是可重复的(假设您希望它在上午 10:00 响起,它将在每天上午 10:00 响起)。
该功能必须:
- 能够为每个闹钟设置“响铃 X 分钟前”,保持闹钟“已播放”的状态,在响铃时更改显示屏的颜色,但还不是时间。
- 能够知道给定警报响起之前的时间。
- 携带其他杂项数据用于显示目的(和网络通知)。
问题
我尝试了许多使用 RxJS 进行建模的方法,但由于我的需要,这些设计总是存在重大缺陷。这是我尝试过的,以及失败的原因:
使用订阅,基于基本上每 1 秒发出一次的刻度主题(因为精度必须为 1 秒)。
这很糟糕,因为我存储了很多订阅,并且每当我编辑警报时,我都必须销毁它们并从最新的数据库更改中重新创建它们(更不用说它是一个实时数据库,因此更新可以来自服务器而无需由当前客户)。
使用每秒调度一次的 NgRx 操作来触发检查警报响起的效果。
再次非常糟糕,因为在这里我丢失了一些数据,因为我找不到在这种行为中存储自定义数据的正确方法,也使得“警报前的剩余时间”监控非常困难。
总的来说,问题是糟糕的设计,我找不到实现这种行为的正确方法,主要是因为我想避免每秒调用一个方法,但另一方面我似乎找不到另一种方法这样做,可能是因为我对这个解决方案持封闭态度,这就是我在这里的原因。
解决方案
首先,我将创建一个可以自行调度并包含其状态的 Alarm 类:
class Alarm {
public lastRangTime = 0;
private stopper = new Subject<void>();
get hasRang() {
return this.lastRangTime > 0;
}
get remaining() {
return this.ringTime - Date.now();
}
// add more metadata
constructor(public ringTime: number, public interval: number) {}
start(): Observable<number> {
return timer(this.ringTime - Date.now(), this.interval)
.pipe(
tap(() => {
this.lastRangTime = this.ringTime;
this.ringTime += this.interval;
}),
takeUntil(this.stopper)
)
}
stop() {
this.stopper.next();
}
}
还有一些容器/服务来保存所有订阅:
class AlarmScheduler {
private queue = new Subject<Alarm>();
private subscription: Subscription = null;
schedule(ringTime: number, interval: number = DEFAULT_INTERVAL) {
const alarm = new Alarm(ringTime, interval);
this.queue.next(alarm);
return alarm;
}
initialize() {
this.subscription = this.queue
.pipe(mergeMap(alarm => alarm.start()))
.subscribe();
}
destroy() {
this.subscription.unsubscribe();
}
}
比您可以简单地从AlarmScheduler
. 他们将以给定的间隔重复自己。
const scheduler = new AlarmScheduler();
scheduler.initialize();
const a1 = scheduler.schedule(Date.now() + 5000);
const a2 = scheduler.schedule(Date.now() + 10000);
工作示例:https ://stackblitz.com/edit/typescript-uft7up
当然,您必须制定一些细节,但就安排警报而言,我希望上面的代码足以让您入门。
推荐阅读
- javascript - 主题 ui 嵌入中的高度
- vba - Lookup value in Access table without a unique identifier using VBA
- servicenow - ServiceNow 监听器
- kotlin - 从适配器接收数据到DetailsActivity?
- batch-file - .bat 批处理文件如何从字符串中获取环境变量?
- r - 使用 ggplot 对两个变量进行排序并重新排序
- sql-server - 通过返回重复项聚合不带组
- matplotlib - 取另一个列值在条形图中进行注释
- google-chrome - 使用 MapBox loadImage 函数时,仅在 Chrome 中出现 AWS S3 CORS 错误
- azure - “允许请求者批准他们自己的更改”的描述令人困惑