我真的想不出你想要这样的 observable 的任何情况:
const formIdValid = defer(() => of(this.filterFrm.valid));
它基本上只是使用一点额外的计算能力来阅读this.filterFrm.valid,无论您订阅哪里。
例如,您的解决方案可以像这样重写,没有任何问题:
this.filterFrm.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged(),
map(frmValue => ({
frmValue,
isValid: this.filterFrm.valid,
})),
tap(console.dir),
filter(({ isValid }) => isValid),
map(({ frmValue }) => ({
searchPhrase: frmValue.filterFld,
startDate: frmValue.startDateFld ? new Date(frmValue.startDateFld) : undefined,
endDate: frmValue.endDateFld ? new Date(frmValue.endDateFld) : undefined
})),
takeUntil(this.destroy)
).subscribe(
filterCriteria => this.filterChanged.emit(filterCriteria)
);
或者如果你不关心你的console.dir日志是有效的,那么这也是一样的:
this.filterFrm.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged(),
tap(console.dir),
filter(_ => this.filterFrm.valid),
map(frmValue => ({
searchPhrase: frmValue.filterFld,
startDate: frmValue.startDateFld ? new Date(frmValue.startDateFld) : undefined,
endDate: frmValue.endDateFld ? new Date(frmValue.endDateFld) : undefined
})),
takeUntil(this.destroy)
).subscribe(
filterCriteria => this.filterChanged.emit(filterCriteria)
);
旁白:defer 到底在做什么?
考虑以下几点:
let num = 10;
const $1 = of(num);
const $2 = defer(()=>of(num));
const $3 = of(1).pipe(map(_ => num));
const $4 = of(1).pipe(mapTo(num));
num++;
$1.subscribe(console.log);
$2.subscribe(console.log);
$3.subscribe(console.log);
$4.subscribe(console.log);
如果你运行这个,你期望输出什么?要正确回答这个问题,您需要了解的是 num 的值何时被解析。对于$1 和$4,这是在创建可观察对象时完成的,这意味着您将获得num 的第一个值。对于$2 和$3,num 在调用defer/map 的 lambda 时被解析。
-
defer 在订阅之前不会调用其工厂函数。
-
map 每次有新值到达时都会调用它的转换函数,最早是在订阅之后的一段时间。
因此,defer 和 map 最终都访问了 num 的第二个值
输出
10
11
11
10
返回this.filterFrm.valid
问题来自 this.filterFrm.valid 解决后。一个函数(在本例中为 filter 的 lambda)在调用之前不会访问该变量。过滤器只有在获得新值时才会调用该函数,因此对于每个新值,过滤器都会重新访问this.filterFrm.valid。
所以在这种情况下,defer 没有任何好处