简体   繁体   English

等待通过RxJ解决的承诺

[英]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. 如果您想忽略值,那么debouncethrottleaudit都是不错的选择。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM