[英]Wait for a promise to resolve with RxJs
I'm trying to implement a "save on type" feature for a form using RxJS v5 beta . 我正在尝试使用RxJS v5 beta为表单实现“保存类型”功能。
The data should be posted to the backend as the user types into the text fields. 当用户在文本字段中键入内容时,数据应发布到后端。 I'm creating a
Rx.Subject
to fire new events ( next()
) for new user input and post it with HTTP requests. 我正在创建一个
Rx.Subject
以为新用户输入触发新事件( next()
),并将其与HTTP请求一起发布。
I've used this question as a starting point: RxJS wait until promise resolved 我以这个问题为起点: RxJS等到答应解决
However, with the solution from this post, simultaneous request to the backend are sent. 但是,使用此帖子中的解决方案,将同时向后端发送请求。
My goal is to only send one request and defer following requests until a running request has completed. 我的目标是仅发送一个请求,然后将后续请求推迟到运行中的请求完成为止。 After completion of the request the last of the pending events should be emitted (like it is the case in
debounceTime
) 请求完成后,应发出最后一个未决事件(就像
debounceTime
的情况一样)
The example
function in the following snippet uses the approach from the linked SO question. 以下代码段中的
example
函数使用链接的SO问题中的方法。 This sends requests for all the input values. 这将发送所有输入值的请求。
The workaround
function function uses a promise stored outside of the "stream" to block and wait for a previous request. workaround
功能使用存储在“流”外部的promise来阻止并等待先前的请求。 This works and only sends a request for the last input value. 这有效,并且仅发送对最后一个输入值的请求。 But that seems to not follow the concept of RxJs and feels hacky.
但是,这似乎不符合RxJs的概念,并且感觉很hack。
Is there a way to achieve this with 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>
If you want to run requests in order and not discard any of them then use concat()
or concatMap()
operators. 如果
concatMap()
顺序运行请求而不丢弃任何请求,请使用concat()
或concatMap()
运算符。 These wait until the previous Observable completes and then continue with the next one. 这些等待直到上一个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');
This prints to console: 打印到控制台:
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
See live demo: https://jsbin.com/xaluvi/4/edit?js,console 观看现场演示: https : //jsbin.com/xaluvi/4/edit?js,控制台
If you wanted to ignore values then debounce
, throttle
or audit
are all good choices. 如果您想忽略值,那么
debounce
, throttle
或audit
都是不错的选择。
Edit : In newer RxJS versions you don't even need to use fromPromise
(or from
) and just return the Promise in concatMap
. 编辑 :在较新的RxJS版本中,您甚至不需要使用
fromPromise
(或from
),只需在concatMap
返回Promise。
You can create observable from a promise and use use delayWhen operator in order to wait until that observable emits (promise resolves). 您可以根据承诺创建可观察对象,并使用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));
Each emit should be delayed by 3 seconds. 每次发射应延迟3秒。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.