我在管道中的操作很长。该链的子部分代表某种高级操作。因此,例如,代码可能类似于
firstObservable().pipe(
// FIRST high level operation
map(param_1_1 => doStuff_1_1(param_1_1)),
concatMap(param_1_2 => doStuff_1_2(param_1_2)),
concatMap(param_1_3 => doStuff_1_3(param_1_3)),
// SECOND high level operation
map(param_2_1 => doStuff_2_1(param_2_1)),
concatMap(param_2_2 => doStuff_2_2(param_2_2)),
concatMap(param_2_3 => doStuff_2_3(param_2_3)),
)
为了提高代码的可读性,我可以如下重构上面的示例
firstObservable().pipe(
performFirstOperation(),
performSecondOperation(),
}
performFirstOperation() {
return pipe(
map(param_1_1 => doStuff_1_1(param_1_1)),
concatMap(param_1_2 => doStuff_1_2(param_1_2)),
concatMap(param_1_3 => doStuff_1_3(param_1_3)),
)
}
performSecondOperation() {
return pipe(
map(param_2_1 => doStuff_2_1(param_2_1)),
concatMap(param_2_2 => doStuff_2_2(param_2_2)),
concatMap(param_2_3 => doStuff_2_3(param_2_3)),
)
}
现在,整个工作正常,我个人发现第二个版本中的代码更易读。不过我松散的是performFirstOperation()
返回参数param_2_1
的信息,然后performSecondOperation()
使用该参数。
在不丢失从子管道到 sub-pipe 的参数信息的情况下,是否有其他策略可以打破长管道链?
答案 0 :(得分:0)
在这里撇开forkJoin的不当用法,如果要保留该数据,则应进行一些不同的设置:
CREATE TABLE student (
student_id INT auto_increment primary key,
name VARCHAR(20),
major VARCHAR(20)
);
INSERT INTO student (name, major)
VALUES ('jack', 'biology');
通过这种方式,您已在高级运算符内部构建了第二条管道,以便可以保留第一组操作中的数据,并在第二组操作结束后使用内部映射来收集数据。 / p>
出于可读性方面的考虑,您可以执行类似的操作:
firstObservable().pipe(
map(param_1_1 => doStuff_1_1(param_1_1)),
swtichMap(param_1_2 => doStuff_1_2(param_1_2)),
// forkJoin(param_1_3 => doStuff_1_3(param_1_3)), this isn't an operator
concatMap(param_2_1 => {
const param_2_2 = doStuff_2_1(param_2_1); // run this sync operation inside
return doStuff_2_2(param_2_2).pipe(
concatMap(param_2_3 => doStuff_2_3(param_2_3)),
map(param_2_4 => ([param_2_1, param_2_4])) // add inner map to gather data
);
})
)
另一种解决方案将涉及多个订户:
firstObservable().pipe(
performFirstOperation(),
performSecondOperation(),
}
performFirstOperation() {
return pipe(
map(param_1_1 => doStuff_1_1(param_1_1)),
swtichMap(param_1_2 => doStuff_1_2(param_1_2)),
// forkJoin(param_1_3 => doStuff_1_3(param_1_3)), this isn't an operator
)
}
performSecondOperation() {
return pipe(
concatMap(param_2_1 => {
const param_2_2 = doStuff_2_1(param_2_1);
return doStuff_2_2(param_2_2).pipe(
concatMap(param_2_3 => doStuff_2_3(param_2_3)),
map(param_2_4 => ([param_2_1, param_2_4]))
);
})
)
}
然后您可以独立订阅每个管道。
答案 1 :(得分:0)
我将一个复杂的操作分解为两个这样的内容:
主要代码
dataForUser$ = this.userSelectedAction$
.pipe(
// Handle the case of no selection
filter(userName => Boolean(userName)),
// Get the user given the user name
switchMap(userName =>
this.performFirstOperation(userName)
.pipe(
switchMap(user => this.performSecondOperation(user))
))
);
首次操作
// Maps the data to the desired format
performFirstOperation(userName: string): Observable<User> {
return this.http.get<User[]>(`${this.userUrl}?username=${userName}`)
.pipe(
// The query returns an array of users, we only want the first one
map(users => users[0])
);
}
第二操作
// Merges with the other two streams
performSecondOperation(user: User) {
return forkJoin([
this.http.get<ToDo[]>(`${this.todoUrl}?userId=${user.id}`),
this.http.get<Post[]>(`${this.postUrl}?userId=${user.id}`)
])
.pipe(
// Map the data into the desired format for display
map(([todos, posts]) => ({
name: user.name,
todos: todos,
posts: posts
}) as UserData)
);
}
请注意,我使用了另一个运算符(在这种情况下为switchMap
)将值从一个运算符方法传递给另一个运算符。
我在这里闪耀:https://stackblitz.com/edit/angular-rxjs-passdata-deborahk