[译] ECMAScript 的 Observables 提案
栏目: JavaScript · 发布时间: 6年前
内容简介:在之前读ps: 在下文中将以 ES 代替 ECMAScript
在之前读 redux
源码时,遇到了关于 Symbol.observable
的使用,发现从没有看到过这个特性,在国内的技术论坛上逛了许久发现提及此的文章甚少,恰巧今天在摸鱼时发现了一篇聊 ECMAScript
中新提案 observables
的文章,故翻译出来加深印象~
ECMAScript 中的 Observables 提案
ps: 在下文中将以 ES 代替 ECMAScript
本文介绍的是当前还在ES提案阶段中的observables特性,在下文中通过本文,我们将带你了解该提案,该提案的api,以及一些使用案例
在写下这篇文章的时候, javascript
的 Observables(观察)
正在通过 RXJs、Bacon.js
等各种类库逐渐普及。Jafar Husain,这位长久以来主张函数式编程的 Netfix
的技术leader(同时也是TC39的委员)也提出了将 observables
集成到我们 js core
中的议案,并且已经通过了 stage1(征求意见阶段)
且已经确定该提案即将进入 stage2(草案阶段)
。
Observable
和 observer
的api
在当前提案中, Observable
是一个内建的被用来处理事件流的类, Obsservalbe
的构造函数可以接受一个定义事件流的回调函数。在接下来的例子中,我们的 observable
将只返回值为1或者2的事件流。 observer.next
方法是用来在 observalbe
流中添加事件的:
new Observable(observer => { observer.next(1); observer.next(2); }) 复制代码
我们也可以使用 observer.error
来记录在流处理时遇到的错误:
new Observable(observer => { observer.error(new Error(`Failed to stream events`)) }) 复制代码
我们还可以使用 observer.complete
来在流处理完结的时候发出信号:
new Observable(observer => { observer.next(1) observer.next(2) observer.complete() }) 复制代码
传递给我们 Observable
构造函数的这个回调函数会返回一个清理我们Observable实例的方法,它可以执行清理事件监听,定时任务等等类似的清理任务。举个例子,当然这个例子就要比上面这些有趣的多了,他追踪了用户在移动鼠标时,光标相对于页面的位置,并同时产生了描述当前光标坐标的事件流:
function mouseTracking () { return new Observable(observer => { const handler = ({ pageX, pageY }) => { observer.next({ x: pageX, y: pageY }) } document.body.addEventListener(`mousemove`, handler) return () => { document.body.removeEventListener(`mousemove`, handler) } }) } 复制代码
为了订阅一个 Observable
的事件流,我们会使用 Observable
实例上的 subscribe
方法,这样做会调用我们之前实例化 Observable
时传入的回调函数,绑定事件的监听,并且启动整个事件流。这样做之后我们就能在移动鼠标的时候在事件流里捕获到它啦:
mouseTracking().subscribe({ next({ x, y }) { console.log(`New position: ${ x }, ${ y }`) }, error(err) { console.log(`Error: ${ err }`) }, complete() { console.log(`Done!`) } }) 复制代码
订阅对象上的 unsubscribe
每次订阅我们都会生成一个订阅对象 Subscription
,这个订阅对象上会有一个 unsubscribe
方法让我们用来取消订阅,执行清理方法(我猜大家应该都还记着之前提到的清理函数吧~),当我们不再需要关注观察流里的事件的时候,just unsubscribe it,让我们将其解放吧。
const subscription = mouseTracking().subscribe({ next({ x, y }) { console.log(`New position: ${ x }, ${ y }`) }, error(err) { console.log(`Error: ${ err }`) }, complete() { console.log(`Done!`) } }) subscription.unsubscribe() 复制代码
Observable.of
Observable.of(...items)
是一个简单有效的能帮助我们从提供的 items
中创建 Observable
的方法,在使用了 Observable.of
方法之后, items
生成的 Observable
实例会在调用 subscribe
的同时生成事件流,返回 items
中的 value
:
Observable.of(1, 2, 3, 4).subscribe({ next(item) { console.log(item) } }) // <- 1 // <- 2 // <- 3 // <- 4 复制代码
我们甚至可以认为, Observable.of
可以理解为跟以下接受一个入参,然后回传事件流的简单例子一样:
Observable.of = (...items) => { return new Observable(observer => { items.forEach(item => { observer.next(item) }) observer.complete() }) } 复制代码
Observable.from
Observable.from
静态方法接受一个类型为对象的入参,如果这个对象中有键值为 Symbol.observable
的方法,那么就会返回这个方法的返回值。
Observable .from({ [Symbol.observable]() { return Observable.of(1, 2, 3) } }) .subscribe({ next(item) { console.log(item) } }) // <- 1 // <- 2 // <- 3 复制代码
当然如果这个传入的对象没有实现 Symbol.observable
,那么我们就假定其传入的是一个可迭代的元素, Observable.from
在这个时候的作用就是将迭代元素遍历并生成一个 Observable
实例,依次将被遍历的结果放入事件流中:
Observable .from([1, 2, 3]) .subscribe({ next(item) { console.log(item) } }) // <- 1 // <- 2 // <- 3 复制代码
在这种情况下,我们的 Observable.from
实现的功能和 Observable.of
是类似的,据此我们甚至可以这样去理解 Observable.from
的实现:
Observable.from = value => { if (typeof value[Symbol.observable] === `function`) { return value[Symbol.observable]() } return Observable.of(Array.from(value)) } 复制代码
结语
虽然现在这个提案还在襁褓之中,但是我相信迟早有一天,其会成为 javascript
的函数式编程的基石。到那天,我相信它还会具有类似 filter
和 map
的能力去处理我们的事件流,让我们在庞大的事件流能够仅仅注重我们需要关注的部分就够了
与此同时,我们的代码格式和开发模式也能在其帮助下变得更加的自然和规范,当然你也可以提前使用我们在github上的的
polyfill
去提前体验它,但是请切记在浏览器环境下删除掉你的 export
关键字。
多个嘴
作为一个英语不是很好的码农,翻译本文还是有点磕磕碰碰,但是总算还是勉勉强强搞定了,希望能够帮助大家多了解一下这个特性,如有错误麻烦诸位指出一下,最后国际惯例,感谢各位的阅读~
以上所述就是小编给大家介绍的《[译] ECMAScript 的 Observables 提案》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- JavaScript的类字段声明(提案)
- Go 1.15 的提案
- 实用!最新的几个 Vue 3 重要特性提案
- 实用!最新的几个 Vue 3 重要特性提案
- FIBOS 超级节点选举以及提案多签介绍
- Babel 7支持ES.Next提案和TypeScript
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。