多个可观察物一起工作 [英] Multiple observables working together

查看:37
本文介绍了多个可观察物一起工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个输入,当用户键入内容时,它会执行实时搜索.例如,假设他搜索了以下内容:

I have an input that as the user types it performs a real-time search. For example, let's say he has searched for the following:

汽车

结果将是:

[
  {
    id: "1"
    name: "Ferrari"
  },
  {
    id: "2"
    name: "Porsche"
  }
]

我能够成功完成此操作,方法如下:

This I was able to do successfully, here is how:

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);
  }

}

视图:

<input type="text" placeholder="Word" (keyup)="search($event)">

我希望用户能够同时键入多个单词,并分别对每个单词执行实时搜索.例如,假设他搜索了以下内容:

I want the user to be able to type multiple words at the same time and perform a real-time search for each word separately. For example, let's say he has searched for the following:

汽车食品防晒霜

car food sun

汽车的结果将是:

[
  {
    id: "1"
    name: "Ferrari"
  },
  {
    id: "2"
    name: "Porsche"
  }
]

食物的结果将是:

[
  {
    id: "3"
    name: "egg"
  },
  {
    id: "4"
    name: "cheese"
  }
]

太阳的结果将是:

[
  {
    id: "5"
    name: "star"
  },
  {
    id: "6"
    name: "sky"
  }
]

还要合并每个单词的结果,在这种情况下,它看起来像这样:

And also merge the results of each word, in this case it would look like this:

[
  [{
      id: "1"
      name: "Ferrari"
    },
    {
      id: "2"
      name: "Porsche"
    }
  ],
  [{
      id: "3"
      name: "egg"
    },
    {
      id: "4"
      name: "cheese"
    }
  ],
  [{
      id: "5"
      name: "star"
    },
    {
      id: "6"
      name: "sky"
    }
  ]
]

但是,假设用户在键入所有单词并执行搜索之后,希望更改其中一个单词.仅需要重新搜索更改过的单词,并且也必须重新合并最终结果.

But let's say that the user, after typing all the words and performing the search, wishes to change one of them. Only the search for the word that was changed needs to be redone, and the merge of the final result would also have to be redone.

我仍然不知道rxjs的所有功能,也不知道什么是实现此目标的理想方法.如果您需要参考,显示目标网站具有非常相似的搜索引擎.

I still do not know all the features of rxjs and I do not know what would be the ideal way to achieve this. If you want a reference, the Display Purposes site has a very similar search engine.

推荐答案

我认为解决方案非常明确.首先,我们必须对单词执行diff算法.过时的单词需要删除,只有新的单词会被请求.

I think the solution is very clear. First, we have to perform a diff algorithm on the words. Stale words need to be removed, only new words will be requested.

唯一的真正问题是我们如何在没有任何数据争用的情况下以最干净的方式实现它.所以我想出一种实现方式:

The only real problem is how we implement it in the cleanest way without any data race. So i come up with one implementation:

searchTags$.pipe(
  scan((pair, tags) => [pair[1] || pair[0], tags], [[]]),
  concatMap(([prevTags, nextTags]) =>
    from(createActions(prevTags, nextTags))
  ),
  reduce((collection$, action) => collection$.pipe(action), of([]))),
  switchMap(stream => stream)
).subscribe(collection => { /*...*/ })

function createActions(prevTags, nextTags) {
  nextTags.reduce((actions, tag) => {
    if (isOld(prevTags, tag)) {
      actions.push(removeAction(tag));
    }
    if (isNew(prevTags, tag)) {
      actions.push(addAction(tag));
    }
    return actions;
  }, []);
}

function removeAction(tag) {
  return map(collection => { collection[tag] = undefined; return collection; });
}

function addAction(tag) {
  return switchMap(collection => requestTag(tag).pipe(map(
    res => { collection[tag] = res; return collection; }
  )));
}

那是我能做的最短的事情!

That's the shortest that i can do!

这篇关于多个可观察物一起工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆