У меня есть функция getNews(), которая в основном возвращает запрос angular http.get. Результатом запроса является массив идентификаторов. Я хотел бы перебрать этот массив, который я получил, и запустить еще один запрос http.get (функция getItem(id)), который затем вернет единственный объект Id, полученный с сервера.

Я пробовал использовать это так:

  getLatest() {
    return this.http.get('all_news_url')
    .map(res => res.json())
    // I even tried creating Observable from array and get only 5 elements
    //.map(res => Observable.from(res.json()))
    //.take(5)
    .map((data) => this.getItem(data))
    .subscribe(
      data => {
        console.log(data);
      }
    )
  }

  getItem(itemId: any): Observable<any> {
    console.log('item id', itemId);

    return this.http.get(this.generateUrl(`item/${itemId}`))
    .map(res => res.json());
  }

Очевидно, это не работает. параметр функции getItem() всегда передается как целый массив идентификаторов.

Спасибо всем за участие в этом вопросе.

11
gregor 23 Июн 2016 в 23:14

2 ответа

Лучший ответ

Вероятно, вы захотите использовать оператор concatMap вместо map. concatMap сводит возвращаемый Observable к исходному Observable, а map возвращает наблюдаемый или наблюдаемый.

Если вы хотите, чтобы данные из getItem () располагались в том же порядке, что и в 'all_news_url', вы можете попробовать что-то вроде

this.http.get('all_news_url')
.concatMap(res => Observable.from(res.json()).take(5))
.concatMap((data) => this.getItem(data))
.subscribe(
  data => {
    console.log(data);
  }
);

С помощью приведенного выше кода вызовы getItem () будут синхронными, то есть будет только один запрос к 'item / $ {itemId}' за раз, и по порядку

Если вам не важен порядок и вы хотите ускорить их, отправляя несколько запросов за раз, измените вторую concatMap на mergeMap. Обратите внимание, что запросы (на item / itemId) будут по-прежнему в порядке, но нет никакой гарантии относительно порядка ответов. Вы можете указать максимальное количество одновременных запросов в качестве третьего параметра для mergeMap (игнорируя второй параметр, передав undefined или null).

.concatMap(res => Observable.from(res.json()).take(5))
.mergeMap((data) => this.getItem(data), null, 3)

Передача 1 в качестве третьего параметра mergeMap будет эквивалентна concatMap

14
Can Nguyen 9 Июл 2016 в 19:25
1
Это именно то, что я искал. Есть всего одна небольшая опечатка: в первой части кода, который вы опубликовали, нет необходимости в .map(res => res.json()). Большое тебе спасибо.
 – 
gregor
25 Июн 2016 в 18:24
1
Ты прав @gregor. Копировал и вставлял, не особо обращая внимания;)
 – 
Can Nguyen
26 Июн 2016 в 14:41

Проблема

  • / list -> Item []
  • / item? item_id = {id} -> Предмет с дополнительным содержимым
  • давайте получим Item [] с дополнительными вещами

Решение concatMap для zip itemRequests

getList(): Observable<Item> {
  return this.http.get('/list').pipe(
    concatMap(list => {
      const itemRequests = list.map(item => this.getItem(item))
      return zip(...itemRequests)
    })
  )
}

getItem(item: Item): Observable<Item> {
  return this.http.get(`/item?item_id=${item.id}`)
}

< Сильный > Готово !

getList().subscribe((items: Item[]) => {
  console.log(items)
})
1
Blake Tiemann 5 Май 2021 в 22:25