Angular 多个观测值协同工作
我有一个输入,当用户键入时,它会执行实时搜索。例如,假设他搜索了以下内容: 汽车 结果将是:Angular 多个观测值协同工作,angular,reactjs,react-native,rxjs,observable,Angular,Reactjs,React Native,Rxjs,Observable,我有一个输入,当用户键入时,它会执行实时搜索。例如,假设他搜索了以下内容: 汽车 结果将是: [ { id: "1" name: "Ferrari" }, { id: "2" name: "Porsche" } ] [ { id: "1" name: "Ferrari" }, { id: "2" name: "Porsche" } ] [ { id: "3" name: "eg
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "3"
name: "egg"
},
{
id: "4"
name: "cheese"
}
]
[
{
id: "5"
name: "star"
},
{
id: "6"
name: "sky"
}
]
我成功地做到了这一点,以下是如何做到的:
class WordComponent {
word: Subject<string> = new Subject<string>();
result: any[] = [];
constructor(private http: Http) {
this.subscribe();
}
subscribe(): void {
this.word.debounceTime(400)
.distinctUntilChanged()
.switchMap((word: string): Observable<any[]> => this.http.get(word))
.subscribe((result: any[]): any[] => this.result = result);
}
search(event: any): void {
this.word.next(event.target.value);
}
}
食物的结果是:
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "3"
name: "egg"
},
{
id: "4"
name: "cheese"
}
]
[
{
id: "5"
name: "star"
},
{
id: "6"
name: "sky"
}
]
sun的结果是:
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
]
[
{
id: "3"
name: "egg"
},
{
id: "4"
name: "cheese"
}
]
[
{
id: "5"
name: "star"
},
{
id: "6"
name: "sky"
}
]
并合并每个单词的结果,在这种情况下,它将如下所示:
[
[{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
],
[{
id: "3"
name: "egg"
},
{
id: "4"
name: "cheese"
}
],
[{
id: "5"
name: "star"
},
{
id: "6"
name: "sky"
}
]
]
subscribe(): void {
this.word.debounceTime(400)
.distinctUntilChanged()
.switchMap((words: string): Observable<any[]> =>
Observable.forkJoin(words.split(' ').map(word => this.http.get(word)))
)
.map(arrayWithArrays => [].concat(arrayWithArrays)
.subscribe((result: any[]): any[] => this.result = result);
}
但假设用户在键入所有单词并执行搜索后,希望更改其中一个单词。只有对已更改单词的搜索需要重新进行,最终结果的合并也必须重新进行
我仍然不知道rxjs的所有特性,也不知道实现这一点的理想方式是什么。如果你想要一个参考,这个网站有一个非常相似的搜索引擎。我想你需要这样的东西:
[
[{
id: "1"
name: "Ferrari"
},
{
id: "2"
name: "Porsche"
}
],
[{
id: "3"
name: "egg"
},
{
id: "4"
name: "cheese"
}
],
[{
id: "5"
name: "star"
},
{
id: "6"
name: "sky"
}
]
]
subscribe(): void {
this.word.debounceTime(400)
.distinctUntilChanged()
.switchMap((words: string): Observable<any[]> =>
Observable.forkJoin(words.split(' ').map(word => this.http.get(word)))
)
.map(arrayWithArrays => [].concat(arrayWithArrays)
.subscribe((result: any[]): any[] => this.result = result);
}
subscribe():void{
此.word.debounceTime(400)
.distinctUntilChanged()
.switchMap((字:字符串):可观察=>
Observable.forkJoin(words.split(“”).map(word=>this.http.get(word)))
)
.map(arrayWithArrays=>[].concat(arrayWithArrays)
.subscribe((结果:any[]):any[]=>this.result=result);
}
我想出了一个巨大但不全面的解决方案:
在这里拉小提琴:
Rx.Observable.prototype.combineAllCont=函数(){
设lastValues=[];
返回Rx.Observable.create(obs=>{
设i=0;
让订阅=此。订阅(流=>{
常数streamIndex=i;
subscription.add(stream.subscripte)(res=>{
lastValues[streamIndex]=res;
obs.next(最新值);
}));
i++;
});
退订;
});
}
/**要演示的内容**/
让搜索框=[
'',
“汽车”,
“汽车”,
“汽车食品”,
“汽车食品太阳”,
“猫粮太阳”,
“猫太阳”
]
函数性能搜索(word){
返回接收可观察延迟(()=>{
console.log('发送对'+word'的搜索);
返回Rx.observative.of({
字:字,
结果:word.split(“”)
});
})
}
设searchBoxStream=Rx.可观测间隔(500)
.take(searchBox.length*2)
.map((i)=>searchBox[i%searchBox.length]);
/**好东西从这里开始**/
让wordsStream=searchBoxStream
.map((str)=>str.trim().split(“”).filter((w)=>w.trim()!=“”));
让wordSearchSubjects=[];
让wordSearchStreamSubject=new Rx.ReplaySubject(1);
wordsStream.subscribe((单词)=>{
const nWords=单词长度;
const nsobjects=wordSearchSubjects.length;
//更新流
对于(i=0;iperformSearch(w))
.concat(Rx.Observable.of(false))//结束信号
)
wordSearchSubjects[i].next(words[i]);
}
//删除流
for(i=nWords;iarr.filter((r)=>r!==false));
resultingStream=wordSearchStream
.map((arr)=>{
设ret=[];
arr.forEach(搜索=>{
ret.push(搜索结果);
});
返回ret;
})
.subscribe((arr)=>console.log(arr));
需要改进的事项:
combineAll
实现,它不会等待原始流完成。如果没有正确实现,这可能会导致内存泄漏,并且应该删除完成的内部订阅(现在不会)也许有一个更好、更直接的解决方案,但我可以想出这个乱七八糟的问题。感觉非常不舒服/危险。我认为解决方案非常清楚。首先,我们必须对单词执行一个diff算法。需要删除陈旧的单词,只需要请求新单词 唯一真正的问题是我们如何以最干净的方式实现它,而不存在任何数据竞争。因此,我提出了一个实现:
searchTags$.pipe(
扫描((对,标记)=>[对[1]| |对[0],标记],[]),
concatMap(([prevTags,nextTags])=>
来自(createActions(prevTags,nextTags))
),
减少([])的((集合$,操作)=>集合$.pipe(操作),
开关映射(流=>流)
).subscribe(集合=>{/*…*/})
函数createActions(prevTags、nextTags){
nextTags.reduce((操作、标记)=>{
if(isOld(前置标签、标签)){
动作。推(移除动作(标签));
}
如果(isNew(prevTags,tag)){
actions.push(addAction(tag));
}
返回动作;
}, []);
}
函数removeAction(标记){
返回映射(集合=>{collection[tag]=undefined;返回集合;});
}
函数addAction(标记){
返回switchMap(collection=>requestTag(tag).pipe(map(
res=>{collection[tag]=res;返回集合;}
)));
}
这是我能做的最短的了 我认为这是一个非常有趣的问题,但我不确定只使用rxjs操作符就可以解决这个问题。。。提取流中的单个单词并找出哪些单词发生了变化,这是一个非常复杂的逻辑。我想知道这是如何解决的。我同意这是一个很好的问题,我会在有时间的时候尽快给出答案;)我认为罗宾·迪克霍夫的回答是一个很好的开始……这样你就可以重新调用那些没有c的单词