2017-01-22 6 views
0

Я использую rxjs сделать несколько запросов HTTP, и я хочу, чтобы в конечном итоге с объектом, который выглядит примерно так:Несколько RxJS AJAX запросов

{ 
    100: { 
    ...response from api call... 
    }, 
    205: { 
    ...response from api call... 
    }, 
    ...etc... 
} 

Вот что я до сих пор:

const projectIds = [100, 205, 208, 300] 
const source = Rx.Observable 
    .from(projectIds) 
    .flatMap(id => get(`projects/${id}/builds`)) 
    .map(response => response['data']) 
    .zip(projectIds) 
    .toArray() 

source.subscribe(pipelines => { 
    console.log(pipelines) 
}) 

Это возвращает мне массив массивов, где первым элементом является ответ от вызова, а второй элемент - это идентификатор проекта.

Проблема заключается в том, что ответ не соответствует идентификатору проекта, так как ответы возвращаются в разных порядках, в зависимости от того, какой запрос завершается первым.

Как я могу сохранить заказ (или, по крайней мере, знать, какой projectId идет с каждым ответом), а также заканчивая объектом в конце (в настоящее время это массив)?

ответ

1

Просто используйте flatMap с elementSelector перегрузки:

.flatMap(
    projectId => getProjectDetails(projectId), 
    (projectId, details) => ({ id: projectId, details }) 
) 

function getProjectDetails(id){ 
    return get(`projects/${id}/builds`) 
    .map(response => response['data']); 
} 

Это позволит вам объединить входной аргумент и каждое выходное значение из flatMap по мере необходимости, эффективно сохраняя контекст. Если вам требуется, чтобы порядок вывода остался прежним, вы можете использовать .concatMap, но затем все выбросы выполняются друг за другом, а не одновременно.

Тогда, наконец, использовать .reduce объединить все объекты обратно в один большой эмиссии:

.reduce((acc, curr) => acc[curr.id] = curr.details, {}) 
2

Вариант 1

Instread из flatMap вы могли бы использовать concatMap, которые должны сохранять порядок.

Примечание: это не приведет к одновременным запросам, если это то, что вы ищете.


Вариант 2

Если вы хотите сделать одновременные запросы (по крайней мере, со стороны RxJS, в зависимости от браузера это еще может быть ограниченно) можно использовать некоторые конструкции, используя forkJoin как следующее :

const projectIds = [100, 205, 208, 300] 
const source = Rx.Observable 
    .from(projectIds) 
    .map(id => get(`projects/${id}/builds`).pluck('data')) 
    .toArray() 
    .switchMap(requestArray => Rx.Observable.forkJoin(requestArray)) 
    .zip(projectIds) 


source.subscribe(pipelines => { 
    console.log(pipelines) 
})