我试图找出在瞬态失败后如何实现重新连接到observable,从最后一个发射值继续。
假设我有以下方法:
interface MyQuery {
fromId: number;
toId: number;
}
interface MyItem {
id: number;
val: string;
}
function observeUnstable(query: MyQuery): Observable<MyItem>;
方法observableUnstable
允许订阅发出值的流,并在间歇性连接失败时发出以下错误:
class DisconnectedError extends Error;
我想编写一个新的observable,它将包装上面的原始observable并透明地重新订阅上一个订阅失败的位置。
数据类型将是不透明的,所以我想使重新连接逻辑通用,可能作为接受高阶选择器函数的运算符:
let startQuery = { fromId: 1, toId: 10 };
let reconnectable = observeUnstable(startQuery)
.lift(new ReconnectOperator<MyItem>((err, lastValue?) => {
if (err instanceof DisconnectedError) {
// This error indicates that we've been disconnected,
// resubscribing from the place we have stopped
let continueQuery = {
fromId: lastValue ? lastValue.id + 1 : startQuery.fromId,
toId: startQuery.toId
};
return observeUnstable(continueQuery);
} else {
// Rethrowing error we don't expect
throw err;
}
}));
以下是 ReconnectOperator 和 ReconnectSubscriber :
class ReconnectOperator<T> implements Operator<T, T> {
constructor(private handler: (err: any, lastValue?: T) => Observable<T>) {
}
call(subscriber: Subscriber<T>, source: any): any {
return source.subscribe(new ReconnectSubscriber(subscriber, this.handler));
}
}
class ReconnectSubscriber<T> extends Subscriber<T> {
private lastValue?: T;
constructor(destination: Subscriber<T>, private handler: (err: any, lastValue?: T) => Observable<T>) {
super(destination);
}
protected _next(value: T) {
this.lastValue = value;
super._next(value);
}
error(err: any) {
if (!this.isStopped) {
let result: Observable<T>;
try {
result = this.handler(err, this.lastValue);
} catch (err2) {
super.error(err2);
return;
}
// TODO: ???
result.subscribe(this._unsubscribeAndRecycle());
// this._unsubscribeAndRecycle();
//this.source.subscribe(result);
//this.add(subscribeToResult(this, result));
}
}
}
此订阅者与 CatchSubscriber 非常相似,只有一个区别是CatchSubscriber在选择器方法中返回原始observable,在我的情况下我想返回最后一个值,以便选择器可以使用它来组成一个品牌新的可观察性,而不是重用原始的。
但是我以某种方式搞砸了重新订阅逻辑,因此生成的observable永远不会为少量测试值返回完成,并且因为更大量的测试值而导致堆栈溢出崩溃。
此外,我的想法是实现一个新的运算符,但是如果可以使用现有运算符的组合在单个方法中以通用方式实现它,那就更好了:)
替代方法的示例,但没有运算符:
function observeStable<T, Q>(
query: Q,
continueQueryFunc: (query: Q, lastValue?: T) => Observable<T>
): Observable<T> {
return observeUnstable<T>(query).catch((err, ???) =>
if (err instanceof DisconnectedError) {
let lastValue = ???
let continueQuery = continueQueryFunc(query, lastValue);
return observeUnstable(continueQuery);
} else {
throw err;
}
);
}