返回介绍

第一部分 类型和语法

第二部分 异步和性能

B.2.2 响应序列

发布于 2023-05-24 16:38:21 字数 3379 浏览 0 评论 0 收藏 0

有了这个非常简要的 Observable(以及 F/RP)的概述给予我们灵感和激励,现在我要展示“响应式 Observable”的一个小子集的修改版,我称之为“响应式序列”。

首先,让我们从如何使用名为 react(..) 的 asynquence 插件工具创建一个 Observable 开始:

var observable = ASQ.react( function setup(next){
  listener.on( "foobar", next );
} );

现在,来看看如何定义一个能“响应”这个 observable 的序列(在 F/RP 中,这通常称为“订阅”):

observable
.seq( .. )
.then( .. )
.val( .. );

所以,只要结束 Observable 链接就定义了序列。很简单,是不是?

在 F/RP 中,事件流通常从一系列函数变换中穿过,比如 scan(..) 、map(..) 、reduce(..) ,等等。使用响应式序列的话,每个事件从一个序列的新实例中穿过。我们来看一个较具体的例子:

ASQ.react( function setup(next){
  document.getElementById( "mybtn" )
  .addEventListener( "click", next, false );
} )
.seq( function(evt){
  var btnID = evt.target.id;
  return request(
    "http://some.url.1/?id=" + btnID
  );
} )
.val( function(text){
  console.log( text );
} );

这个响应序列的“响应”部分来自于分配了一个或多个事件处理函数来调用事件触发器(调用 next(..) )。

响应序列的“序列”部分就和我们已经研究过的序列完全一样:每个步骤可以使用任意合理的异步技术,从 continuation 到 Promise 再到生成器。

一旦建立起响应序列,只要事件持续触发,它就会持续启动序列实例。如果想要停止响应序列,可以调用 stop() 。

如果响应序列调用了 stop() ,停止了,那你很可能希望事件处理函数也被注销。可以注册一个 teardown 处理函数来实现这个目的:

var sq = ASQ.react( function setup(next,registerTeardown){
  var btn = document.getElementById( "mybtn" );

  btn.addEventListener( "click", next, false );

  // 一旦sq.stop()被调用就会调用
  registerTeardown( function(){
    btn.removeEventListener( "click", next, false );
  } );
} )
.seq( .. )
.then( .. )
.val( .. );

// 将来
sq.stop();

处理函数 setup(..) 中的 this 绑定引用和响应序列 sq 一样,所以你可以使用这个 this 引用向响应序列定义添加内容,调用像 stop() 这样的方法,等等。

这里是一个来自 Node.js 世界的例子,使用了响应序列来处理到来的 HTTP 请求:

var server = http.createServer();
server.listen(8000);

// 响应式observer
var request = ASQ.react( function setup(next,registerTeardown){
  server.addListener( "request", next );
  server.addListener( "close", this.stop );

  registerTeardown( function(){
    server.removeListener( "request", next );
    server.removeListener( "close", request.stop );
  } );
});

// 响应请求
request
.seq( pullFromDatabase )
.val( function(data,res){
  res.end( data );
} );

// 节点清除
process.on( "SIGINT", request.stop );

使用 onStream(..) 和 unStream(..) ,触发器 next(..) 也很容易适配节点流:

ASQ.react( function setup(next){
  var fstream = fs.createReadStream( "/some/file" );

  // 把流的"data"事件传给next(..)
  next.onStream( fstream );

  // 侦听流结尾
  fstream.on( "end", function(){
    next.unStream( fstream );
  } );
} )
.seq( .. )
.then( .. )
.val( .. );

也可以通过序列合并来组合多个响应序列流:

var sq1 = ASQ.react( .. ).seq( .. ).then( .. );
var sq2 = ASQ.react( .. ).seq( .. ).then( .. );

var sq3 = ASQ.react(..)
.gate(
  sq1,
  sq2
)
.then( .. );

主要的一点是:ASQ.react(..) 是 F/RP 概念的一个轻量级的修改版,也是术语“响应序列”的意义所在。响应序列通常能够胜任基本的响应式用途。

这里有一个使用 ASQ.react(..) 管理 UI 状态的例子(http://jsbin,com/rozipaki/6/edit?js,output ),还有一个通过 ASQ.react(..) 处理 HTTP 请求 / 响应流的例子(https://gist.github.com/getify/bba5ec0de9d6047b720e )。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文