问题
I have some code that looks like
//service.ts
addProduct(productId) {
this.http.post('someUrl', ReqData).map(json).subscribe(doStuff);
}
//component.ts
addAllproducts(productsIds) {
productIds.forEach(productId => service.addProduct(productId);
}
What I want is to be able to wait for each call to finish before calling for the next productId, without using window.setTimeout
..
回答1:
First return the observable from your service method:
addProduct(productId) {
return this.http.post('someUrl', ReqData).map(json).subscribe(doStuff);
}
And use a recursive function and call it in the subscribe
callback for each of the items in your array:
let loop = (id: number) => {
service.addProduct(id)
.subscribe((result) => {
// This logic can be modified to any way you want if you don't want to mutate the `producIds` array
if (productIds.length) {
loop(productIds.shift())
}
})
}
loop(productIds.shift())
回答2:
How about some recursive calls using .expand()?
First, create a recursive function and map the data for recursive use:
const recursiveAddProduct = (currentProductId, index, arr)=>{
return service.addProduct(currentProductId)
.map((response)=>{
return {
data:response,
index: index+1,
arr:arr
}
})
};
Now, call it recursively in your component:
//productIds is an array of Ids
//start of using the first index of item, where index = 0
let reduced = recursiveAddProduct(productIds[0],0,productIds)
.expand((res)=>{
return res.index>res.arr.length-1 ? Observable.empty(): recursiveAddProduct(productIds[res.index],res.index,productIds)
});
reduced.subscribe(x=>console.log(x));
Here is a working JSBin
Benefit of using .expand
operator:
- You are still using Observables and can chain whatever operators you want to.
- You are calling one http after another, which is your requirement.
- You don't need to worry about error handling, they are all chained to a single stream. Just call a
.catch
to your observables. - You can do anything to your recursion method (data manipulation,etc)
- You can set the condition when to terminate the recursion call.
- One-liner (almost) code.
Edit
You can use .take()
operator to terminate your recursion, if you don't like the inline ternary, like this:
let reduced = recursiveAddProduct(productIds[0],0,productIds)
.expand(res=>recursiveAddProduct(productIds[res.index],res.index,productIds))
.take(productIds.length)
Working JSBin
回答3:
You can use the Observable.merge(). Try something like that
addProduct(productId):Observable<Response> {
return this.http.post('someUrl', productId);
}
addAllproducts(productsIds) {
let productedsObservable:Observable<Response>[]=[];
for(let productID in productsIds){
this.productedsObservable.push(this.addProduct(productID));
}
return Observable.merge(productedsObservable)
}
You need to subscribe to the requested function for it the execute the http request. You can read more about combination operators (like merge) here
来源:https://stackoverflow.com/questions/45035184/chaining-http-calls-in-angular-2-in-a-for-loop