简体   繁体   English

多个RxJS AJAX请求

[英]Multiple RxJS AJAX Requests

I'm using rxjs to make several http requests and I want to end up with an object that looks something like: 我正在使用rxjs发出几个http请求,但最终要得到一个看起来像这样的对象:

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

Here's what I have so far: 这是我到目前为止的内容:

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

This gives me back an array of arrays where the first element is the response from the call and the second element is the id of the project. 这给了我一个数组数组,其中第一个元素是调用的响应,第二个元素是项目的ID。

The problem is that the response doesn't match the project id as the responses come back in different orders depending on which request completes first. 问题在于响应与项目ID不匹配,因为响应会以不同的顺序返回,具体取决于哪个请求首先完成。

How can I preserve the order (or at least know which projectId goes with each response) while also ending up with an object at the end (currently is an array)? 我如何保留顺序(或至少知道每个响应都带有哪个projectId),同时最后还要有一个对象(当前是一个数组)?

Option 1 选项1

Instread of flatMap you could use concatMap , that should preserve the order. 的Instread flatMap你可以使用concatMap ,应保持秩序。

Note: This won't make any concurrent requests though, if that is what you are looking for. 注意:如果这是您要查找的内容,则不会发出任何并发请求。


Option 2 选项2

If you want to make concurrent requests (at least from the RxJS side, depending on the browser this could still be limited) you could use some construct using forkJoin like the following: 如果要发出并发请求(至少从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)
})

Just use the flatMap with elementSelector overload: 只需将flatMapelementSelector重载一起使用:

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

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

This will let you combine the input argument and every output value from flatMap as you require, effectively preserving context. 这样,您就可以根据需要组合输入参数和flatMap的每个输出值,从而有效地保留上下文。 If you require the output order to stay the same you can use .concatMap but then all emissions are done after each other instead of concurrently. 如果您要求输出顺序保持不变,则可以使用.concatMap但是所有排放都是彼此接连而不是同时进行的。

Then finally use a .reduce to combine all objects back to one big emission: 然后最后使用.reduce将所有对象组合成一个大发射:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM