在 RxJS 中何时使用 tap() 和何时使用 map()

Apu*_*hak 2 rxjs angular2-observables

该文档使用以下代码描述了 tap():

import { fromEvent } from 'rxjs';
import { tap, map } from 'rxjs/operators';

const clicks = fromEvent(document, 'click');
const positions = clicks.pipe(
  tap(ev => console.log(ev)),
  map(ev => ev.clientX),
);
positions.subscribe(x => console.log(x));
Run Code Online (Sandbox Code Playgroud)

但我不明白为什么要使用水龙头。它只是记录。解释说

将每次点击映射到该点击的 clientX 位置,同时记录点击事件

Jon*_*wag 5

轻敲

对源 Observable 的每次发射执行副作用,但返回与源相同的 Observable

例子:

tap(value => console.log(value))
Run Code Online (Sandbox Code Playgroud)

地图

将给定的项目函数应用于源 Observable 发出的每个值,并将结果值作为 Observable 发出。

例子:

map(value => 'prefix' + value)
Run Code Online (Sandbox Code Playgroud)

为什么不使用 map 或其他运算符来处理 log 等副作用

您可以使用 map、scan 和任何其他获取函数并返回单个结果的运算符来实现副作用。这将使您的代码在将来很难理解/调试/查找错误。前提是,通常在管道中使用副作用是不好的。如果您需要/想要它并且不想为每个日志记录点进行大量订阅,则日志记录可能是一个例外。因此,tap 很有用。您可以将其调整为以下步骤:

  1. 尽量避免副作用
  2. 如果您需要一些(记录)使用点击来澄清有副作用

您如何可以但不应该的示例

switchMap(value => {
  console.log(value); // Side effect 1
  const newValue = foo(value);
  console.log(newValue); // Side effect 2
  return of(newValue);
})
Run Code Online (Sandbox Code Playgroud)

你可以和应该如何做的例子

tap(console.log), // Side effect 1
switchMap(value => of(foo(value))),
tap(console.log) // Side effect 2
Run Code Online (Sandbox Code Playgroud)

最后一句话:当您最初编写没有带来太多好处的代码时。你的项目越大,其他人试图找到错误的那一刻,它就会大大节省时间。