使用 Javascript 进行反应式编程

Posted

技术标签:

【中文标题】使用 Javascript 进行反应式编程【英文标题】:Reactive programming with Javascript 【发布时间】:2016-06-29 03:51:47 【问题描述】:

我是响应式编程的新手,阅读所有这些我无法理解的文章我有点迷茫。

实际上,我是一名来自 Nodejs、Angularjs、Angular 2 和 React 的 javascript 开发人员。

我做什么

我一直使用 Promise,用于远程数据获取、本地异步解析等...比回调更好的可测试性并满足我的需求。

我对流的理解

我不知道流在哪里可以拯救我,除非在特殊情况下。

这种特殊情况是我不能在监听流时使用 Promise,因为 Promise 只会被解析一次。

SocketIo 示例:

io.on('connection',  (socket) => 
  // this works
);

io.on('connection').then((socket) => 
  // this can't work, promise would be resolved only once
);

如果我没记错的话,我可以通过简单地返回一个 observable 来使用响应式流来管理这种情况。对吧?

我不明白的地方

我正在研究 Angular 2 和周围的所有东西。实际上,在许多博客中,人们习惯于使用 observables 来获取远程数据,我无法理解使用它而不是 promises 有什么优势。

事实上,在这两种情况下我都需要制作一个遥控器,那么为什么一个比另一个多呢?这是性能问题吗?

我需要什么

如果您已经阅读了整个问题,我需要了解在远程数据获取的情况下使用响应式编程而不是 Promise 的优势是什么?

在哪些情况下(其他情况)使用反应性的东西比使用普通的东西更好?

【问题讨论】:

阅读本期,会澄清很多github.com/angular/angular/issues/5876 【参考方案1】:

基本上,如果您有一个异步事件,您不想收到有关(回调)的通知,您可以使用Promise。如果您预计会发生一系列事件,请使用Observable

Observable 相对于Promise 的优势

Observable 可以取消 Observable 是惰性的(在订阅之前不要做任何事情) Observable 可以做 Promise 可以做的事情,但只有使用 Observable 才能让您以相同的方式编写代码(使用 rx 运算符而不是 .then(),无论您期待一个或一系列事件。

【讨论】:

嗨!我知道这是一个古老的答案,但我可能不清楚一件事。 observables 是否可以为以后的订阅者保留返回值,类似于已经解决的承诺将立即成为.then()d?此外,您能否在不影响其操作的情况下拥有多个订阅者来订阅 observable(例如,进行两次异步调用)如果您认为值得提出自己的问题,我可以这样做。 BehaviorSubject 创建一个Observable,它会立即将最后一个值返回给新订阅者。 .share() 操作员进行Observable 多播,每个事件都传递给每个订阅者。注意 - 您需要显式导入运算符(如 mapshare、...)。【参考方案2】:

@Günter 为您提供了 observables 的基础,尤其是调用 Promise 的能力。

更进一步,我认为 observables 的主要优势是能够使用运算符构建异步数据流/流。

以下是一些具体的用例:

debounceTime/switchMap。当您想利用表单输入根据相应的 HTTP 请求过滤列表时,您需要用于请求的值是用户完成写入时的值。不必发送多个请求:每个新字符一个(一个用于“s”,一个用于“so”,一个用于“som”,...,一个用于“搜索的东西”)。 debounceTime 运算符通过缓冲事件来实现这一点,并在一段时间不活动后提供最后一个事件。

这是一个示例:

@Component(
  (...)
  template: `
    <input [ngFormControl]="ctrl"/>
  `
)
export class MyComponent 
  constructor() 
    this.ctrl = new Control();
    this.ctrl.valueChanges
               .debounceTime(500)
               .distinctUntilChanged()
               .switchMap((vallue: string) => 
                 // Get data according to the filled value
                 return this.service.getData(entry);
               )
               .subscribe(data => 
                 // Update the linked list
                 this.list = data;
               );
  

如果您只使用switchMap,则每个输入将有一个请求,但之前正在进行的请求将被取消。这可以让您获得正确的结果,尤其是在某些请求的请求执行时间较长的情况下。

在这种情况下,您可以将 Web UI 中的事件(DOM 事件)链接到 HTTP 请求以相应地执行(对事件做出反应)并应用一些高级行为。

实施重试。通过混合retryWhendelaytimeout 运算符,您可以轻松(且透明地)实现重试

searchPlaces(searchText:string) 
  var params = new URLSearchParams();
  params.set('placename_startsWith', searchText);
  params.set('username', 'templth');

  return this.http.get('http://api.geonames.org/postalCodeSearchJSON',
       search: params )
    .retryWhen(error => error.delay(500))
    .timeout(2000, return new Error('delay exceeded'))
    .map(res => res.json().postalCodes);

我认为这就是 observables 的真正力量:异步处理链/数据流并基于事件链接应用程序的不同部分。这是使用 Promise 无法完成的事情,并且允许实现用例以使您的应用程序更加健壮。

这里有一系列文章可以为您提供更多详细信息:

https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html http://slides.com/robwormald/everything-is-a-stream https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

【讨论】:

以上是关于使用 Javascript 进行反应式编程的主要内容,如果未能解决你的问题,请参考以下文章

无法在javascript反应中更改警报消息的颜色

[转] Java, 使用 Reactor 进行反应式编程

iOS Swift:如何为 Swift 3 进行异步/反应式/事件编程

反应式编程与事件驱动编程有何不同?

反应式和功能反应式编程之间的区别

在反应式编程中无法访问第二个函数之外的变量