假设我要下载10,000个文件。我可以轻松地建立这10,000个文件的队列(如果可以做的更好,我们很乐意为您提供建议),
import request from 'request-promise-native';
import {from} from 'rxjs';
let reqs = [];
for ( let i = 0; i < 10000; i++ ) {
reqs.push(
from(request(`http://bleh.com/${i}`))
)
};
现在我有一个Rx.JS数组,它是根据表示队列的Promise创建的。现在针对我想要的行为,我要发布
我可以为这个问题创建解决方案,但是鉴于Rxjs queue之类的东西(我从未使用过),我想知道最正确的Rxjs方法是什么。
答案 0 :(得分:1)
听起来您想要一个等效的forkJoin
,以支持呼叫者指定的最大并发订阅数。
可以使用forkJoin
重新实现mergeMap
并暴露concurrent
参数like this:
import { from, Observable } from "rxjs";
import { last, map, mergeMap, toArray } from "rxjs/operators";
export function forkJoinConcurrent<T>(
observables: Observable<T>[],
concurrent: number
): Observable<T[]> {
// Convert the array of observables to a higher-order observable:
return from(observables).pipe(
// Merge each of the observables in the higher-order observable
// into a single stream:
mergeMap((observable, observableIndex) => observable.pipe(
// Like forkJoin, we're interested only in the last value:
last(),
// Combine the value with the index so that the stream of merged
// values - which could be in any order - can be sorted to match
// the order of the source observables:
map(value => ({ index: observableIndex, value }))
), concurrent),
// Convert the stream of last values to an array:
toArray(),
// Sort the array of value/index pairs by index - so the value
// indices correspond to the source observable indices and then
// map the pair to the value:
map(pairs => pairs.sort((l, r) => l.index - r.index).map(pair => pair.value))
);
}
答案 1 :(得分:0)
我在 2021 年遇到了同样的问题,并且能够利用 @cartant's answer,所以我想我会分享:
index.ts
import request from 'request-promise-native';
import { from, defer } from "rxjs";
import { forkJoinConcurrent } from './forkJoinConcurrent';
const handleRequest = async (id: string) => await request.get(`http://bleh.com/${id}`, { json: true });
const ids: string[] = [...Array(10000).keys()].map((k: number) => k.toString());
const concurrent: number = 3;
/* use `defer` instead of `from` to generate the Observables.
`defer` uses a factory to generate the promise and it will execute
the factory only when it is subscribed to */
const observables = ids.map((id: string) => defer(() => from(handleRequest(id))))
forkJoinConcurrent<any>(observables, concurrent).subscribe(value => console.log(value));
forkJoinConcurrent.ts
import { from, Observable } from "rxjs";
import { last, map, mergeMap, toArray } from "rxjs/operators";
export function forkJoinConcurrent<T>(
observables: Observable<T>[],
concurrent: number
): Observable<T[]> {
// Convert the array of observables to a higher-order observable:
return from(observables).pipe(
// Merge each of the observables in the higher-order observable
// into a single stream:
mergeMap((observable, observableIndex) => observable.pipe(
// Like forkJoin, we're interested only in the last value:
last(),
// Combine the value with the index so that the stream of merged
// values - which could be in any order - can be sorted to match
// the order of the source observables:
map(value => ({ index: observableIndex, value }))
), concurrent),
// Convert the stream of last values to an array:
toArray(),
// Sort the array of value/index pairs by index - so the value
// indices correspond to the source observable indices and then
// map the pair to the value:
map(pairs => pairs.sort((l, r) => l.index - r.index).map(pair => pair.value))
);
}