2017-01-22 83 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) 
}) 

这给了我一个数组的数组,其中第一个元素是来自调用的响应,第二个元素是项目的ID。

问题是响应与项目ID不匹配,因为响应以不同顺序返回,具体取决于哪个请求首先完成。

如何保持顺序(或至少知道哪个projectId与每个响应一起),同时最后还有一个对象(当前是一个数组)?

回答

1

只需使用flatMapelementSelector超载:

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