从返回observable的函数提前返回错误

时间:2017-09-07 07:55:10

标签: error-handling rxjs reactive-programming

我有一个函数和一个验证帮助函数,它将一个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;从箭头函数里面?

3 个答案:

答案 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异步流中执行所有操作,则会增加认知过载并分散您想要解决的实际问题。所以,即使你想练习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的主体内。

您要做的是:

  1. 尽快抛出参数验证错误。这使您可以选择同步处理它,这也意味着如果您在RxJS中使用它(例如,在switchMap中),它仍然会沿着observable的错误通道向下传播。
  2. 将您的subscribe来电链接到您想要采取的下一个操作中。这实际上与你需要做的诺言没什么不同(想想validHeadersObsvalidate.then(returnAthing)在这种情况下没有太大的不同)。
  3. 您当前代码中的问题是您正在开始这项工作 订阅,它是异步的所以它不会返回,然后你继续和 回归“幸福之路”可观察。如果回归“快乐的道路” observable取决于验证调用的异步反馈, 你需要链接它。

    (小注意,如果任何tsv处理逻辑碰巧是异步的,你会想要使用validate.map(returnAthing)而不是switchMap

    这应该这样做:

    map