等待承诺用RxJ解决

时间:2016-11-14 11:34:56

标签: javascript rxjs rxjs5

我正在尝试使用RxJS v5 beta为表单实现“保存类型”功能。

当用户键入文本字段时,数据应发布到后端。我正在创建一个Rx.Subject来为新用户输入触发新事件(next())并使用HTTP请求发布它。

我用这个问题作为起点:RxJS wait until promise resolved

但是,根据此帖子的解决方案,会同时向后端发送请求。

我的目标是只发送一个请求并推迟跟踪请求,直到正在运行的请求完成。完成请求后,应发出最后一个待处理事件(如debounceTime中的情况)

以下代码段中的example函数使用链接的SO问题中的方法。这会发送对所有输入值的请求。

workaround函数函数使用存储在“stream”之外的promise来阻止并等待先前的请求。这可以工作,只发送最后一个输入值的请求。但这似乎并不遵循RxJs的概念而且感觉很糟糕。

有没有办法用RxJS实现这个目标?

function fakeRequest(value) {
  console.log('start request:', value)
  return new Promise((resolve) => { 
    setTimeout(() => resolve(value), 1000);
 });
}

function example() {
  let subject = new Rx.Subject();
  
  subject
    .debounceTime(500)
    .switchMap(input => fakeRequest(input))
    .subscribe(data => console.log(data))

  subject.next('example value 1');
  subject.next('example value 2');
  subject.next('example value 3');
  subject.next('example value 4');
}


function workaround() {
  let subject = new Rx.Subject();

  let p = Promise.resolve();
  subject
    .debounceTime(500)  
    .switchMap(input => p.then(() => input))
    .do(input => p = fakeRequest(input))
    .subscribe(data => console.log(data))

  subject.next('workaround value 1');
  subject.next('workaround value 2');
  subject.next('workaround value 3');
  subject.next('workaround value 4');
}

example();
// workaround();
<script src="https://unpkg.com/@reactivex/rxjs@5.0.0-rc.2/dist/global/Rx.js"></script>

2 个答案:

答案 0 :(得分:5)

如果您想按顺序运行请求而不丢弃任何请求,请使用concat()concatMap()运算符。这些等待直到上一个Observable完成,然后继续下一个Observable。

function fakeRequest(value) {
  console.log('start request:', value)
  return new Promise((resolve) => { 
    setTimeout(() => resolve(value), 1000);
 });
}

let subject = new Subject();
subject.concatMap(value => Observable.fromPromise(fakeRequest(value)))
  .subscribe(value => console.log(value));

subject.next('example value 1');
subject.next('example value 2');
subject.next('example value 3');
subject.next('example value 4');

打印到控制台:

start request: example value 1
example value 1
start request: example value 2
example value 2
start request: example value 3
example value 3
start request: example value 4
example value 4

查看现场演示:https://jsbin.com/xaluvi/4/edit?js,console

如果您想忽略值,那么debouncethrottleaudit都是不错的选择。

修改:在较新的RxJS版本中,您甚至不需要使用fromPromise(或from),只需返回concatMap中的承诺。

答案 1 :(得分:0)

您可以根据承诺创建可观察对象并使用use delayWhen运算符,以便等到该可观察对象发出(承诺解决)为止。

import { timer } from 'rxjs';
import { delayWhen, from } from 'rxjs/operators';

const myPromise = new Promise(resolve => setTimeout(resolve, 3000)); // will resolve in 3 sec


const waitable = timer(0, 1000).pipe(delayWhen(() => from(myPromise)));
waitable.subscribe(x => console.log(x));

每次发射应延迟3秒。