管道 rxjs 运算符如何可能受到后续运算符返回值的影响?
How is a piped rxjs operator possibly affected by a subsequent operator's returned value?
为了检查 rxjs 管道中运算符之间的中间值,我尝试使用 tap 将它们简单地记录到控制台。
我有两个水龙头,一个在用于对数组进行排序的映射运算符之前,一个在它之后。令我惊讶的是,对于两次点击,记录了相同的排序数组,而我希望首先看到原始顺序,然后是排序的数组。
因此 map 运算符中的排序会影响之前的 tap 运算符使用的 observable。尽管如此,操作员的功能似乎如预期的那样一个接一个地执行,因为第二张地图的日志记录在水龙头的日志之间。
我的代码(我打算稍后用合适的类型替换 Observable 数组的类型):
public getJSONData(): Observable<any[]> {
return this.http.get(this.poisJSONPath).pipe(
map((featureCollection: any) => featureCollection.features),
tap((features) => console.log(features)),
map((features: any) => {
console.log('this is logged in between as expected');
return features.sort((a, b) =>
a.properties.name > b.properties.name ? 1 : -1
);
}),
tap((features) => console.log(features))
);
}
我假设我缺少 rxjs 管道操作模式的一些基本特征。在我发现的所有其他示例中,水龙头似乎按我的预期工作。我在这里错过了什么?
最简单(但不仅如此)的答案是数组已经排序。
进一步调查,当我 运行 这个:
of({
features: [3,4,7,1,3,8]
}).pipe(
pluck('features'),
tap(console.log),
map(features => {
console.log('this is logged in between as expected');
return features.sort(
(a, b) => a > b ? 1 : -1
);
}),
tap(console.log)
).subscribe(console.log);
这是我的输出:
[3,4,7,1,3,8]
this is logged in between as expected
[1,3,3,4,7,8]
[1,3,3,4,7,8]
所以,这可能与您 运行 所在的环境有关。
例如,如果 console.log
被缓冲 - 那么即使保留打印顺序,数组在打印之前可能已经在内存中更改。
考虑
RxJS 不对内存中的内容做出任何保证。这就是为什么我们鼓励您使用纯的、不可变的函数。让你的程序逻辑更容易推理。
考虑一下:
const delayedLog = val => setTimeout(() => console.log(val), 1000);
of({a: 5}).pipe(
tap(delayedLog),
map(input => {
delayedLog("this is logged in between as expected");
input.a++;
return input;
}),
).subscribe(delayedLog);
输出:
{"a":6}
this is logged in between as expected
{"a":6}
{"a":6}
被打印两次,即使在调用第一个延迟日志时 a = 5。这是因为在控制台从内存中读取值之前内存中的值发生了变化。
VS
const delayedLog = val => setTimeout(() => console.log(val), 1000);
of({a: 5}).pipe(
tap(delayedLog),
map(input => {
delayedLog("this is logged in between as expected");
return { a: input.a + 1 }
}),
).subscribe(delayedLog);
{"a":5}
this is logged in between as expected
{"a":6}
这里我们得到了预期的输出,因为我们没有改变我们的对象,我们 return 一个具有增量值的新对象。
开始寻找的地方
尝试对数组的浅表副本进行排序,看看是否可以解决问题。
public getJSONData(): Observable<any[]> {
return this.http.get(this.poisJSONPath).pipe(
pluck('features'),
tap(console.log),
map((features: any[]) => {
console.log('this is logged in between as expected');
return [...features].sort((a, b) =>
a.properties.name > b.properties.name ? 1 : -1
);
}),
tap(console.log)
);
}
为了检查 rxjs 管道中运算符之间的中间值,我尝试使用 tap 将它们简单地记录到控制台。
我有两个水龙头,一个在用于对数组进行排序的映射运算符之前,一个在它之后。令我惊讶的是,对于两次点击,记录了相同的排序数组,而我希望首先看到原始顺序,然后是排序的数组。
因此 map 运算符中的排序会影响之前的 tap 运算符使用的 observable。尽管如此,操作员的功能似乎如预期的那样一个接一个地执行,因为第二张地图的日志记录在水龙头的日志之间。
我的代码(我打算稍后用合适的类型替换 Observable 数组的类型):
public getJSONData(): Observable<any[]> {
return this.http.get(this.poisJSONPath).pipe(
map((featureCollection: any) => featureCollection.features),
tap((features) => console.log(features)),
map((features: any) => {
console.log('this is logged in between as expected');
return features.sort((a, b) =>
a.properties.name > b.properties.name ? 1 : -1
);
}),
tap((features) => console.log(features))
);
}
我假设我缺少 rxjs 管道操作模式的一些基本特征。在我发现的所有其他示例中,水龙头似乎按我的预期工作。我在这里错过了什么?
最简单(但不仅如此)的答案是数组已经排序。
进一步调查,当我 运行 这个:
of({
features: [3,4,7,1,3,8]
}).pipe(
pluck('features'),
tap(console.log),
map(features => {
console.log('this is logged in between as expected');
return features.sort(
(a, b) => a > b ? 1 : -1
);
}),
tap(console.log)
).subscribe(console.log);
这是我的输出:
[3,4,7,1,3,8]
this is logged in between as expected
[1,3,3,4,7,8]
[1,3,3,4,7,8]
所以,这可能与您 运行 所在的环境有关。
例如,如果 console.log
被缓冲 - 那么即使保留打印顺序,数组在打印之前可能已经在内存中更改。
考虑
RxJS 不对内存中的内容做出任何保证。这就是为什么我们鼓励您使用纯的、不可变的函数。让你的程序逻辑更容易推理。
考虑一下:
const delayedLog = val => setTimeout(() => console.log(val), 1000);
of({a: 5}).pipe(
tap(delayedLog),
map(input => {
delayedLog("this is logged in between as expected");
input.a++;
return input;
}),
).subscribe(delayedLog);
输出:
{"a":6}
this is logged in between as expected
{"a":6}
{"a":6}
被打印两次,即使在调用第一个延迟日志时 a = 5。这是因为在控制台从内存中读取值之前内存中的值发生了变化。
VS
const delayedLog = val => setTimeout(() => console.log(val), 1000);
of({a: 5}).pipe(
tap(delayedLog),
map(input => {
delayedLog("this is logged in between as expected");
return { a: input.a + 1 }
}),
).subscribe(delayedLog);
{"a":5}
this is logged in between as expected
{"a":6}
这里我们得到了预期的输出,因为我们没有改变我们的对象,我们 return 一个具有增量值的新对象。
开始寻找的地方
尝试对数组的浅表副本进行排序,看看是否可以解决问题。
public getJSONData(): Observable<any[]> {
return this.http.get(this.poisJSONPath).pipe(
pluck('features'),
tap(console.log),
map((features: any[]) => {
console.log('this is logged in between as expected');
return [...features].sort((a, b) =>
a.properties.name > b.properties.name ? 1 : -1
);
}),
tap(console.log)
);
}