Meteor 是一个实时 full stack JavaScript 框架。 Reactivity 是它的一个非常重要的特点。官网上列出了 Meteor 的 7 大原则或者说是特点:
Data on the Wire. Meteor 不发 HTML ,服务器端只负责发送数据,让客户端来渲染
One Language. 前后端都是 JavaScript 语言
Database Everywhere. 前后端都可以直接创建存取修改数据库里的数据,并且安全
Latency Compensation. Meteor 在前端提前获取数据并模拟数据模型,使其看起来像是从服务器端立即返回了数据
Full Stack Reactivity. 实时相应是 Meteor 的缺省配置。在所有层面,从数据库到模板,都会在必要时自动更新
Embrace the Ecosystem. Meteor 完全开源并集成了很多现有的开源工具和框架。例如 Angular , React 。 Meteor 有自己的 AtmosphereJS 包下载管理应用,也可直接使用 NPM (目前是非官方支持)
Simplicity Equals Productivity. Meteor 简单易上手, API 简介优美
可能还有人不理解什么是 Reactivity 。简单来说 Reactivity 就是数据传递的一种模式,特别是如何传递数据的变化。一种编程语言或者框架如果能够自动传递数据的变化,不需要用户再编写代码去更新使用到的变量,那么我们就说它是 reactive 的。
比如 Meteor 和 facebook 的 React 框架就是这么处理数据变化的,不需要额外的代码。如果 reactive 的变量发生了变化,那么框架会自动再次运行使用到这个变量且具有 reactive 特性的代码段 - 这里引入了一个 reactive computation/context (程序的上下文,一般是一个函数) 概念。如果配合使用 React , React 会自动在 virtual dom 上比较,然后只渲染更新了的那一小部分,而不是再把所有涉及到的无论变化与否的 view 都再渲染一次。这样不用自己再写代码来指定更新的地方,代码就更容易维护,前端的开发和运行效率都有提高。
举个例子。a = b + c
,如果 b 是 1 , c 是 2 ,那么 a 的值就是 3 。在不是 reactive 的 函数里,如果 b 的值变为 4 ,什么事情都不会发生,你得自己动手去触发需要更新的地方;而在 reactive 的函数里, a 的值会自动变为 6 。凡是在 Template 里引用 a 的地方都会变为 6 ,而不再需要手动更新。就是 b 和 c 改变了,这个 reactive 函数会被自动调用,再次计算得出 a 的新值 6 。这样代码会少很多,逻辑也更简单,特别是涉及到需要再次渲染 view 的时候。
最后注意,要具备 reactivity ,必须得满足两个条件。第一是要有一个 reactive 的数据源,第二就是这个数据源要在具有 reactive 特性的上下文里被使用。这样可以避免一些不必要的副作用,可以选择不用 reactivity ,如果不需要的话。
Meteor server 端没有 reactivity ,只有 client 端才有。
Meteor 数据库和模板都能自动更新。可以使用 facebook 的 React 使前端组件化,代码会更好维护。可以把 Meteor 看做是 flux 的一种实现,类似 redux 之类的。 Meteor 也可以是 Facebook 新开源的 Relay 的一种实现。甚至某种程度上来说更完善。
Reactivity 主要是基于观察者模式 (Observer Pattern)。可以避免过多地使用回调函数。
下面是 Meteor 里自带的具有 reactive computation 特性的函数:
不过如果使用 React 的话,那就是 <code>mixins: [ReactMeteorData]</code> 这个 mixin 和
<code> getMeteorData()</code> 函数一起使用。
下面介绍几种 Meteor 常用的 reactive 变量。
Meteor 里用得最多的 reactive 变量来源当然是 Mongodb 的 collections 。
Session 是 Meteor 提供的一个只在前端使用的全局 reactive 数据源。
只要 Session.set 被调用并且改变了原值,那么对应的 Session.get 所在的模板或者 reactive 函数就会被自动重新运行。
例如官方给的这个例子:
Tracker.autorun(function () {
Meteor.subscribe("chat-history", {room: Session.get("currentRoomId")});
});
// 下面这条语句会导致上面的 Tracker.autorun 函数再次被执行
// chat-history 的注册也转移到了 home
Session.set("currentRoomId", "home");
注意 Session.get 和 Session.equals 的文档里有这句 "..., invalidate the computation the next time the variable changes to or from the value.", 这句话有点让人难以理解。它的意思是这两个 API 会使其所在的 reactive computation 失效,然后自动再运算。其实就是调用了 Session.set 且改变了原值之后,它所对应的 get 和 equals 所在的 reactive computation 函数会被重新运算一次。
还有如果遇到以下情况:
(1) Session.get("key") === value
(2) Session.equals("key", value)
(2) 比 (1) 要好,可以避免不必要的重新渲染。细节见文档。
但是如果要比较 object 和 array ,不能使用 Session.equals 。建议使用 underscore 的
_.isEqual(Session.get(key), value)
.
另外如果使用 Session.get(), 它返回的是一个克隆值,所以改变返回值没有任何 reactive 效果。
Session 因为是全局的,支持 hot code push 。但是不支持用户 refresh page ,如果 refresh ,值会回到初始值。
这两个未来会合并到后者 ReactiveDict 。主要是用于本地变量。
不使用回调函数就可以实时获得客户端和服务器端连接的变化。
如果没有登录的话,值为 null 。
获得登录状态变化,用于显示登录动画。
类似 subscription 的一个 callback 函数。在 ready() 里, Meteor 会自动处理 unsubscription 和回收 subscription 的 handle 。所以可以重复 subscribe 同一个数据源而不用自己 unsubscribe, 也避免了重复 subscribe 产生数据冲突。 Meteor 还能自动判断已被 unsubscribe 过的数据,如果再次 subscribe 就不会产生 client server 间的重复通信操作。
你也可以使用 Deps 和 Tracker package 创建自己的 reactive 数据源和 computation 。不过这里就不介绍了。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.