我有一个函数和一个验证帮助函数,它将一个tsv文件作为字符串读入。我甚至试图通过使用rxjs执行同步任务来练习我的反应式编程。我知道这可能不是它的完美用例,但我知道它应该是可能的。
这里的伪代码是最简单的形式:
public readTsv(tsv: string): Observable<TsvAsObject> {
if (!tsv || tsv.length < 1) {
return Observable.throw('null or empty tsv file passed');
}
// check tsv headers
this.validHeadersObs(tsv.split('\n')[0]) // pass the first line of the tsv string
.filter(valid => valid === false)
.subscribe(() => {
return Observable.throw('invalid tsv headers')
});
// omitted logic that processes the tsv and then returns it as an observable
return Observable.of(tsvAsObject);
}
我已经测试了我的validHeaders()函数,我知道它有效。它返回一个布尔流来检查每个列标题。只要一对标题不匹配,它就会返回一个Observable.of(false):
private validHeadersObs(headerLine: string): Observable<boolean> {
const headers$ = Observable.from(headerLine.split('\t'));
const validHeaders = ['columnName1', 'columnName2', 'columnName3'];
return headers$
.mergeMap((value, index) => Observable.of(value === validHeaders[index]));
}
问题是readTsv()没有返回Observable.throw('invalid tsv headers')
,因为我不确定如何从订阅中提前返回函数。有没有办法去&#34;双重回报&#34;从箭头函数里面?
答案 0 :(得分:0)
感谢关于角度http服务的this问题,我通过使用Observable.create()
创建自定义Observable来解决问题。我认为这是使用更高阶的可观察量来调用的?无论如何......
public buildMenusFromTsv(tsv: string): Observable<any> {
return Observable.create((observer: Observer<any>) => {
Observable.of((tsv && tsv.length > 0) as boolean)
.filter(valid => valid === false)
.map(() => Observable.throw('null or empty tsv file passed')
.subscribe(err => observer.error(err));
// check tsv headers
this.validHeadersObs(tsv.split('\n')[0])
.filter(valid => valid === false)
.map(() => Observable.throw('invalid tsv headers')
.subscribe(err => observer.error(err));
// omitted logic that processes the tsv and then returns it as an observable
observer.next(Observable.of(tsvAsObject));
observer.complete();
});
}
奖励:我找到了一个时髦的运算符来比较可观察的流而不是笨重的mergeMap()
private validHeadersObs(headerLine: string): Observable<boolean> {
const headers$ = Observable.from(headerLine.split('\t'));
const validHeaders$ = Observable.from(['columnName1', 'columnName2', 'columnName3']);
return headers$.sequenceEqual(validHeaders$);
}
答案 1 :(得分:0)
我建议如下:
如果您尝试在Rx异步流中执行所有操作,则会增加认知过载并分散您想要解决的实际问题。所以,即使你想练习Rx,也不要过分。
private allHeadersAreValid(headerLine: string): boolean {
const validHeadersInOrder = ['columnName1', 'columnName2', 'columnName3'];
return headerLine.split('\t')
.map((field, index) => field === validHeaders[index])
.reduce((acc, curr) => acc && curr, true);
}
subscribe()
,只有Observables
通过在函数内部进行订阅,您将失去Observables的惰性,并且已经在执行可能永远不需要的代码。因为我们现在已经使验证成为同步函数,所以您可以轻松地对其进行测试,并在进行实际工作之前使用它来测试前置条件。
public readTsv(tsv: string): Observable<TsvAsObject> {
if (!tsv || tsv.length < 1) {
return Observable.throw('null or empty tsv file passed');
}
if(!allHeadersAreValid(tsv)) {
return Observable.throw('invalid tsv headers');
}
// omitted logic that processes the tsv and then returns it as an observable
return Observable.of(tsvAsObject);
}
从上面的代码示例开始,您仍然可以在实际subscribing
之前工作,因为allHeadersAreValid
已经过评估。为了使所有内容再次变得懒惰,您可以使用Defer()
将代码的执行推迟到实际的订阅时刻。
public readTsv(tsv: string): Observable<TsvAsObject> {
return Observable.defer(() => {
if (!tsv || tsv.length < 1) {
return Observable.throw('null or empty tsv file passed');
}
if(!allHeadersAreValid(tsv)) {
return Observable.throw('invalid tsv headers');
}
// omitted logic that processes the tsv and then returns it as an observable
return Observable.of(tsvAsObject);
});
}
现在您的验证函数是同步的并且可以轻松测试,但您的readTsv
函数仍然是可观察的,并且仍然是预期的。
答案 2 :(得分:0)
好的,所以看看你想要做什么,我看到一个红旗:在一个将返回一个可观察的函数中,可能不应该有一个define('WC_TEMPLATE_DEBUG_MODE', false);
调用除非它在另一个Observable的主体内。
您要做的是:
subscribe
来电链接到您想要采取的下一个操作中。这实际上与你需要做的诺言没什么不同(想想validHeadersObs
,validate.then(returnAthing)
在这种情况下没有太大的不同)。 您当前代码中的问题是您正在开始这项工作 订阅,它是异步的所以它不会返回,然后你继续和 回归“幸福之路”可观察。如果回归“快乐的道路” observable取决于验证调用的异步反馈, 你需要链接它。
(小注意,如果任何tsv处理逻辑碰巧是异步的,你会想要使用validate.map(returnAthing)
而不是switchMap
)
这应该这样做:
map