RxJS:限制 API 调用速率

Phi*_*hix 5 javascript rxjs

几天来我一直在努力(和搜索)寻找解决方案,虽然以下方法有效,但我不禁觉得有一种更 rxjs-y 的方法可以做到这一点。

我有一组 URL 需要从外部源下载,该源有速率限制,每分钟不超过 100 个调用。

const sources = ['a.jpg', 'b.jpg', 'c.jpg'];

timer(0, 1000).pipe(
  switchMap(index => of(sources[index])),
  takeWhile(_ => _ !== undefined),
  switchMap(url => {
    return from(download(url))
  })
).subscribe(
  next => console.log(next),
  err => console.error(err),
  () => console.info('Done')
)

// Pseudo
function download(url) {
  return new Promise((resolve, reject) => {
    resolve('Downloaded ' + url)
  })
}
Run Code Online (Sandbox Code Playgroud)

看起来有点迂回和老套。

迭代数组以避免每秒过多请求被锁定的最佳方法是什么?

mar*_*tin 4

这取决于您想要延迟的时间,但您可以使用例如保证 1 秒延迟的方法:

import { from, of, merge as mergeStatic, timer } from 'rxjs';
import { delay, concatMap, merge, ignoreElements } from 'rxjs/operators';

const sources = ['a.jpg', 'b.jpg', 'c.jpg'];
const mockRequest = s => of(s)

from(sources)
  .pipe(
    concatMap(url => mergeStatic(
      mockRequest(url),
      timer(1000).pipe(ignoreElements())
    ))
  )
  .subscribe(console.log)
Run Code Online (Sandbox Code Playgroud)

或者,如果您想在请求完成后进行延迟(请求时间+延迟),您可以使用mockRequest(url).pipe(delay(1000)).

如果您想首先发出结果,然后进行交易,您只需切换运算符的顺序即可:

from(sources)
  .pipe(
    concatMap(url => mockRequest(url).pipe(
      merge(timer(1000).pipe(ignoreElements()))
    ))
  )
  .subscribe(console.log)
Run Code Online (Sandbox Code Playgroud)

现场演示:https://stackblitz.com/edit/rxjs6-demo-qwdfgp? file=index.ts