【问题标题】:Observable polling?可观察的投票?
【发布时间】:2017-03-07 20:09:11
【问题描述】:

我目前有一个 Observable 计时器:

private poller(): Observable<PrepareData> {
    return Observable.timer(0, 5000).switchMap(() => this.http.get("/cgi/dashboard.php")).map(res => res.json());
}

我想要它,以便在最后一个完成后 5 秒完成一个获取请求。有什么简单的方法吗?

【问题讨论】:

  • 顺便说一句,您是否只需要 5 秒后的一次 get 请求,还是希望每 5 秒连续请求一次?
  • 每 5 秒连续请求一次,但不希望一次运行多个请求

标签: angular


【解决方案1】:

我将添加我的答案,因为@Maxime 的答案有效,但实际上有 no need for a subject

这是使用.concat() 运算符和getData() 函数递归完成的。

.concat()

通过顺序发射它们的值来连接多个 Observable,一个 Observable 一个接一个。

(...)

concat 将订阅第一个输入 Observable 并发出其所有值,而不会以任何方式更改或影响它们。当该 Observable 完成时,它将订阅然后传递的下一个 Observable,并再次发出其值。这将重复,直到操作员用完 Observables。当最后一个输入 Observable 完成时,concat 也将完成。

(我使用 js 版本来制作一个可以与 stack Overflow 的工具配合使用的 sn-p,但 typescript 也是如此):

function someHTTPCall() {
  // well it's a fake http call
  console.log("making the Http request (can take up to 5s)...");
  return Rx.Observable.of("http response !")
    .delay(Math.round(Math.random() * 5000));
}

function getData() {
  return someHTTPCall()
    .concat(Rx.Observable.timer(5000).switchMap(() => getData()));
}

let myObs = getData();

myObs.subscribe((data) => {
  console.log(data,"waiting for 5 seconds before next request");
});
&lt;script src="https://unpkg.com/rxjs@5.4.0/bundles/Rx.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 如果我转到其他页面如何停止?
【解决方案2】:

这是一个有趣的问题,我很高兴想出了一个解决方案。

此解决方案等待前一个完成如您所愿:

const { Observable, Subject } = Rx

const getFakeHttpRequest$ = () => Observable.of('response !').delay(3000)

const polling$ = new Subject()

Observable
  // need to tick the first time
  .of(null)
  // everytime our polling$ subject will emit, we'll do again what's next
  .merge(polling$)
  // register to a fake request
  .switchMap(_ =>
    getFakeHttpRequest$()
      .do(_ => {
        // once we're here, the request is done
        // no mater how long it was to get a response ...
        console.log('HTTP request done !');

        // ... we wait 5s and then send a new value to polling$ subject
        // in order to trigger a new request
        setTimeout(_ => polling$.next(null), 5000)
      })
  )
  .subscribe()

请注意,我已将请求延迟 3 秒,并且每隔 8 秒就会启动一个新请求,因为我们等待 3 秒等待响应,然后按照您的问题要求等待 5 秒。

这是一个有效的 Plunkr:https://plnkr.co/edit/kXefUbPleqyyUOlfwGuO?p=info

【讨论】:

  • @Maxime 你不需要在这里使用主题。检查我的解决方案。
【解决方案3】:

你可以使用区间操作符:

private poller(): Observable<PrepareData> {
    return Observable.interval(5000).switchMap(() => this.http.get("/cgi/dashboard.php")).map(res => res.json());
}

【讨论】:

  • Interval 是否等待上一个完成?
  • 不这么认为。
【解决方案4】:

基于@n00dl3 的回答,我创建了一个适用于网络的通用轮询方法,并在触发另一个 api 请求之前查看选项卡是否可见。

function getPrice$() {
  return from(
      fetch(API_PRICE_MULTI_URL))
      .then((response) => {
          return response.json();
      })
  );
}

function poll$(pollObservableFactory, pollInterval) {
  return (document.hidden ? empty : pollObservableFactory)().pipe(
       concat(
            timer(pollInterval).pipe(
               switchMap(() => poll$(pollObservableFactory, pollInterval))
            )
       )
  );
}

// and test it like this
const sub=poll$(getPrice$, PRICE_POLL_INTERVAL).subscribe(console.log)

当用户切换到另一个窗口时,投票将不会进行 api 调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 2011-06-09
    • 2011-06-17
    • 1970-01-01
    相关资源
    最近更新 更多