虚拟研讨会:Node.js 生态系统之框架、库、最佳实践

阅读数:21351 2011 年 4 月 21 日

Node.js 是一个服务器端框架,基于 Google 的 V8 JavaScript 引擎创建,旨在利用事件触发、非阻塞的 I/ O 帮助开发人员构建高度可伸缩的网络程序。 目前很多流行的第三方库和框架都使用了 Node.js, InfoQ 联系了其中几个的创建者, 与他们展开了一次虚拟研讨会。

Node.js 的创建者 Ryan Dahl 在 JSConf 2010 上做了演讲,简单介绍了什么是Node.js (PDF) :

  • 服务器端的 JavaScript
  • 基于 Google 的 V8 创建
  • 事件触发、非阻塞的 I/O。 类似于 EventMachine 或 Twisted。
  • CommonJS 模块系统。
  • 有 8000 行 C/C++ 代码, 2000 行 Javascript 代码,14 个贡献者。

Node.js 最近越来越受关注, Yahoo! Mail 的首席工程师 Peter Griess 也提到, 他们公司正在研究如何在产品中使用 Node.js

目前在GitHub 上,大约有三百个项目都与Node.js 有关 ,InfoQ 联系了其中几个最受欢迎项目的创建者, 与他们展开了此次讨论。

参与者包括:

  • 来自 Express 的 TJ Holowaychuk, Express 是受 Sinatra 影响的 Node.js Web 开发框架。(译注: Sinatra 是用 Ruby 编写的开源 Web 应用框架、 领域特定语言。)
  • Socket.IO 的 Guillermo Rauch,Socket. IO 是一个简单的 HTTP 套接字接口实现及服务器。
  • 来自 Geddy 的 Matthew Eernisse,Geddy 是个 Node. js 的 Web 开发框架,类似于 Merb、Rails、 Pylons、Django 等框架。
  • node-xmpp 的 Astro,node- xmpp 是遵循 XMPP 协议的 Node.js 库。
  • StackVM 的 Peteris Krumins 和 James Halliday,StackVM 是一家初创公司, 正尝试用 Node.js 来简化虚拟机在 Web 上的使用。

InfoQ:能向大家简单介绍一下你们的项目么? 项目试图解决什么问题?又是如何去做的呢?

TJ(Express):正如你们所了解的, Express 很大程度上受到了 Sinatra 的影响, 最初主要是想让开发人员在新的平台上自如使用新的语法。 不过我们在 1.x 版本做了很多改进, Express 现在利用了流行的中间件框架 Connect( 我是共同编写者),并移除了一些不适合项目的依赖。

有些 Node 框架只关注自身,但大部分还是想成为“最重要的” 库。我期望 Express 是可选的,不会带来什么局限。

Guillermo(Socket.IO):Socket. IO 提供了一个简单的 API, 可以抽象出各个浏览器在 HTTP 传输实现上的不同, 借此让实时 JavaScript 应用的构建成为可能。

Matthew(Geddy):Geddy 是个全 JavaScript 堆栈的 MVC Web 框架。 Geddy 想让开发人员很容易地用 JavaScript 编写复杂的 Web 应用、在客户端和服务器之间共享代码。

Geddy 使用了现有 MVC 框架中的常见模式, 比如 Rails 和 Django 中用控制器 / 行为、模型、 模板化的函数。 不过 Geddy 中的这些功能都是用 JavaScript 完成的, 所以模型、验证、模板之类的内容也都可以在浏览器中使用。

Geddy 有简单、基于资源的路由机制,还有准确的内容协商, 所以用它来开发传输结构化数据的轻量 Web Service 会超级简单。

Astro(node-xmpp):我的目标是创建一个能在 Node.js 环境中容易使用的 XMPP 库。 先前的库以适用于浏览器的 Strophe.js 为基础, 不符合 Node.js 的约定; 也没有利用 EventEmitter 和支持 SRV 的 DNS 解析器 ,最重要的是,它既不支持 XMPP 客户端,也不支持组件连接。

Peteris 和 James(StackVM):我们的项目叫 StackVM, 它可以借助 HTML 和 JavaScript 让虚拟机在浏览器上运 行。StackVM 显示了虚拟机不绑定到桌面时可以进行的操作。 比如说,用户可以在他们的网站里嵌入虚拟机、 与合作者共享工作内容、为应用创建在线的产品演示, 还可以创建以前不可能实现的 Mashup。

InfoQ:你们项目里的主要模块是什么?它们怎样和其他模块、 Node.js 进行交互?

TJ(Express):Connect 中间件框架在 Expre ss 1.x 里发挥了重要作用,以前称为“插件” 的组件现在都是 Connect“中间件”。 这种抽象意味着社区可以在更短的时间周期内借助所有通用的内容生成强大的框架。Express 1.0 测试版的核心组件和功能有:

  • 强大的路由
  • 视图系统,包括对局部视图和集合视图的支持
  • 基于环境的配置
  • 基于会话的持久、迅速的通知
  • 内容协商
  • 响应工具
  • 重定向工具
  • 能快速生成应用骨架

Guillermo(Socket.IO):Socket. IO 包括一个在浏览器上运行的 JavaScript 客户端, 还有一个在服务器(Socket.IO-node) 上运行的 JavaScript 组件。

Matthew(Geddy):Geddy 是个 MVC 框架。 你可以在“控制器”上定义函数,把 URL 映射到动作上。 还可以创建“模型”,定义控制器中要使用的对象。最后, 你可以通过渲染“视图”对请求作出响应,“视图” 可以是某种模板,或者仅仅是格式化的数据。

Geddy 用 Node.js 实现了它的 HTTP 服务器, 在服务器端执行所有的函数、控制器动作、 模板渲染时也使用了 Node.js。 由于是全 JavaScript 堆栈, 很多相同的代码也是在浏览器中运行的。

Astro(node-xmpp):Node. js 追求可伸缩的服务器软件性能,这点对我来说非常重要。 这就是为什么我在评估可用的 XML SAX 解析器库之后,自己创建了 node-expat 的原因。 Expat 用 C++ 编写, 和快速的解析器库 libexpat 进行了绑定。

我过去经常使用 Ruby XMPP 库 xmpp4r,所以 node- xmpp 仿照了 xmpp4r 的一点儿内容。 客户端和组件都来自于连接,连接进行 XML 流处理。 连接基于普通的 TCP 客户端流, 所以用户仍然能访问原始数据管理、发送队列管理等功能。

Peteris 和 James(StackVM):我们的主要组成 部分就是 StackVM 本身( http://github. com/pkrumins/stackvm/ ), 它使用了我们为 Node.js 编写的几个其他模块:

接着我们用 Socket.IO( http://github. com/LearnBoost/Socket.IO ) 和别人编写的 Socket.IO-node( http:// github.com/LearnBoost/Socket. IO-node )模块来完成浏览器和 StackVM 之间的通信。

StackVM 的工作原理串起来就是: StackVM 使用 node-bufferlist 和 node- rfb 打开一个到虚拟机 VNC 端口的连接。屏幕出现更新时, node-rfb 将更新信息转发给 node-png 或 node- jpeg,由它们生成图像。接着,图像由 Socket. IO 转发给浏览器。DNode 对 Socket. IO 的传输进行了抽象, 用更加异步的方式在服务器和浏览器之间路由消息。

InfoQ:你们选用 Node.js 的主要原因是什么? 日常工作中会有哪些好处?

TJ(Express):大概在一年前, 当我开始做 Express 的时候我对 Node 产生了兴趣。 我希望用熟悉的语言、熟悉而简单的方式去定义 Web 应用。 我听说 Node 不久后就下载了源码、简单阅读了一下, 我喜欢它所引导的方向。用了几年 Ruby 之后, 我发现我越来越喜欢用 JavaScript 了。

Guillermo(Socket.IO):用 Node 编写实时应用真的非常简单。我们选择 Node 的主要原因是, 在 Node 里你是司机, 它能让你只用几行代码就创建出一个自己的 HTTP 服务器。 传统堆栈都没有这种能力,比如常见的 Apache+PHP, 因为 PHP 只能在请求完成时执行,而且要运行一小段时间, 才能生成响应并退出。

另一方面,不用牺牲性能和可伸缩性, Node 的请求就可以延长一段时间,因为 Node 是个完全异步、单线程、单进程的框架。

Matthew(Geddy):我选择 Node.js 是因为, 它是第一个可靠的服务器端 JavaScript 实现, 不以 JVM 为基础。 我在日常工作中编写了很多 JavaScript 代码, 一个很大的优点就是, 不需要针对客户端和服务器端在两种语言之间换来换去。

Astro(node-xmpp):对 IO 操作比较多的应用, 我想控制它们的并发问题。典型的选择是线程编程,但这很昂贵。 Erlang 和 GHC 把轻量级的绿色线程映射到了本地线程上( 一个 CPU 内核有一个本地线程),以此来解决并发问题。 尽管有这一功能,开发人员仍要忍受同步问题、避免竞态条件。

异步编程时不用开发串行的“线程”代码,你会觉得这有些不自然。 但不处理那些麻烦的同步问题确实让我觉得轻松了很多。 一旦你理解了这个概念,就会习惯它带来的“阶梯效应”, 功能会逐层嵌套实现。

Peteris 和 James(StackVM):不用刻意展开或编写 C 代码,Node.js 就有非常棒的性能。Node. js 没有任何需要担心的遗留代码,所有内容自底向上都是异步的。 还有很多库在尝试一些新的事情,比如 websockets, 社区也非常活跃。 在浏览器和服务器端使用相同的语言让代码重用变得更为简单, 而且 JavaScript 语言很简单,能迅速完成原型。

InfoQ:你觉得 Node.js 成为主流的时机成熟了么? 你怎么看它周围的生态系统呢?

TJ(Express):这个问题不太好回答, 和其他很多社区相比,Node.js 仍然很小。 我个人觉得这个项目(和社区)有很大的潜力,而且 Django、 Drupal 或 Ruby on Rails 最终也很有可能会跟进,甚至做出更大的贡献。

Guillermo(Socket.IO):Node 正在非常迅 速地成熟起来。在 GitHub( http://github. com/ry/node )上, 它的追随者现在差不多是 Rails( http:// github.com/rails/rails )追随者的一半, Rails 无疑是最流行的 Web 应用开发框架之一。 而这只用了一段很短的时间。

Matthew(Geddy):对有些目标来说它已经很成熟了, 但人们要像用 Ruby 或 Python 那样去进行通用的开发还为时尚早。也许还需要一两年时间。

Astro(node-xmpp):Node. js 有朝一日会很容易成为主流的, 因为 JavaScript 是个相当流行的语言。

Node.js 一直在发展,你应该经常针对新版本测试你的代码。 如果你打算让任何人都能运行你的代码,却不管用户的 Node. js 版本到底是新还是旧,我觉得这会有问题。

Peteris 和 James(StackVM):它要是在某个方面还不够成熟,我们会让它更加成熟的。它是开源的, 所以我们要是发现一个 Bug、或是需要一些新特性, 必要的话我们会自己进行处理。社区驱动的生态系统非常棒:开源、 很多想法、大量参与其中的开发人员、一大堆文档和博客文章, 还有 GitHub 上每天都会有更新的 Node.js 库。

API 在不同的版本之间确实会略有变化,但 Ryan Dahl 承诺,即将发布的 0.2 版本会具备全新的稳定性。

InfoQ:你在项目或日常工作中使用其他的 Node. js 库或框架么?除了你自己的库,你觉得有没有其他的 Node. js 库或框架是特别有用、别的开发人员也应该去看一看的?

TJ(Express):日常工作中我用了很多自己的库, 还有下面几个库, 我对这几个项目和它们的开发人员怀有深深的敬意:

Guillermo(Socket.IO):我们天天都用 Node。除了 Socket.IO,我支持 Mongoose( http ://github.com/learnboost/ mongoose )和其他一些较小的组件, Mongoose 是一个 ORM 框架,针对 NoSQL、 面向文档的数据库 MongoDB。 

Matthew(Geddy):Node-Jake 是个类似于 Make/ Rake 的 JavaScript 构建工具: http://github.com/mde/node- jake

Logan 是个小型的跨环境测试框架, 可以用它在浏览器里测试只能运行在 Node.js 中的代码( 还有 TheRubyRacer, 它把 V8 嵌套在一个 Ruby 进程中): http://github.com/mde/logan

Astro(node-xmpp):有几个需要提一下。 第一个是 Isaac Schlueter 开发的包管理器 npm。无论什么地方, 你都想拥有包管理器所带来的便利。

TJ Holowaychuk 开发的 ext.js 相当有用: 它用很多方便的方法对基本的 JavaScript 类型进行了增强 ,所有人都会发现这很有用。

不要错过 Senchalab 的 Connect Web 框架。Node.js 内置的 HTTP 支持是它的杀手锏, Connect 想要达到 Rack 在 Ruby 世界中的水平。当然, 这并不像看起来的那么简单,因为它完全是异步的。 

Peteris 和 James(StackVM):借助 Node 包管理器 npm( http://npmjs.org/ )去使用、 发现其他开发人员编写的库是一种非常好的方式。 我们使用 Socket.IO, 它对 WebSocket 进行了抽象, 还对尚没有 WebSocket 的浏览器提供了应变方案, 以支持 WebSocket 式的通信。 我们也一直在尝试基于 Socket.IO 的 node- compress,以便加快把数据传输到浏览器的速度。

InfoQ:如果一个团队要开始使用 Node.js, 他们需要留心哪些陷阱?有提示或“最佳实践”么?

TJ(Express):一般来说都有环境问题。 我认为 Git 是必需的,其他 SCM 都让我觉得不太满意, 实际是有点儿反感。搭建一个持续集成的服务器, 哪怕像 CIJoe( http://github.com/ defunkt/cijoe )那么简单,那也是必需的; 还有就是测试、测试、再测试!我着重强调测试, 我所有的 Node 项目都用“Expresso”( http:// github.com/visionmedia/ expresso )进行测试,“Expresso” 项目支持代码覆盖率报告, 能让你很明确地知道哪些代码没有覆盖到, 这些简单的步骤应该能让项目不停向前滚动。

Guillermo(Socket.IO):我的建议是:

  • 对 JavaScript 语言要有非常强烈、近乎狂热的求知欲。
  • 深刻理解保证网站运转的各个层面。这意味着要理解底层的知识( 熟知 HTTP、协议和网络通常会有较大的帮助)。
  • 对于某些功能,试着“忘记”其他语言实现它们的方式,学习用“ Node”的方式去实现它们( 比如在 Java 里用线程去解决的问题, 你可以用 Node 以不同的方法去轻松解决)

Matthew(Geddy):Node. js 仍然处于发展初期,所以仍然会有 API 的变化, 这会破坏代码。要准备好修改代码, 或者用 Geddy 或 Express 等框架, 框架的作者会屏蔽 Node 的变化,保证 API 的一致性。

Astro(node-xmpp):尽管 JavaScript 的语法微不足道,看过用大括号划分程序代码的任何人都能看懂, 但基于原型的遗留系统一开始还是会造成混乱。 一定要告诉你的伙伴会有什么样的影响。

要是你仍然觉得基于类的遗留系统更容易使用, 那你可能需要找一个处理方式类似于用 JavaScript 处理遗留 Ruby 的库。

Peteris 和 James(StackVM):阻塞 I/O 可能是需要留意的最大陷阱, 因为整个程序等到调用完成之后才会执行其他操作。 只在初始化时使用少量的阻塞调用, 尤其是在编写注重性能的网络服务时。异步 I/ O 和事件驱动编程需要的思维方式和大多数编程都不太相同。 拥抱它吧。

InfoQ:根据你的经验, JavaScript 代码库规模如何像项目那样变得越来越大? 你用的工具有哪些?你觉得工具对现实中的 Node. js 项目支持得怎样?

TJ(Express):我觉得这完全由开发人员来决定。 JavaScript 过去曾是一门“丑陋”的语言, 但现在已经不是了。我觉得行内注释非常重要, 有助于创建可见的空白,而且不会让代码看起来混乱不堪。 至于整个项目的组织,把逻辑块分布到单独文件中绝不会有错, 对任何语言来说这都是通用的做法。

Node 采用了 CommonJS 的模块模式, 这其实是我在语言中使用过的最喜欢的组织工具。最典型的,大多数环境都包含一个扁平的名字空间, 所以在现实中你仍然要随时处理名字空间的冲突, 而 CommonJS 的模块系统就很好地避免了冲突。 

Guillermo(Socket.IO):让 JavaScript 同时在服务器、客户端上运行是很让人兴奋的。 随着招聘变得越来越容易, 整个团队可以处理同一应用的很多不同方面, 我觉得这对公司来说特别重要。 Node 也为专业环境中的开发提供了很多工具:

  • 简单却强大的模块系统(基于 CommonJS)
  • 很多测试框架(Expresso、Vows 等)

Matthew(Geddy):在服务器端, JavaScript 现在和 Ruby、Python 一样, 已经有很多工具了—— CommonJS 模块提供了让代码保持模块化的机制。Node- Jake 等构建工具能让你的构建和打包自动化, 以可预测的方式进行。

客户端的 JavaScript 还需要再多做一点儿工作。 但 JavaScript 对象能很自然地封装功能, 而且 JavaScript 很久以前就有了在客户端进行“ 大规模编程”的最佳实践。 Facebook 等大公司创建了他们自己的框架, 但 Dojo 或 YUI 等更复杂的工具包则需要更多这样的支持。 

Astro(node-xmpp):我推荐在大型项目中使用静态类型。

我也很喜欢测试驱动开发;不知道 Node. js 社区是否已经选择了测试库的事实标准。

Peteris 和 James(StackVM):Node. js 有一个模块系统,它对项目的可伸缩性大有裨益, 但大型软件项目不论用什么语言,一般都有更多的 Bug, 而且比小型项目更难测试。对于 StackVM, 我们将功能分解为可重用、开源的模块, 以此来尽可能长久地避免大型代码库的这种缺陷。到目前为止, 这种方法让 StackVM 的主要代码库更为灵活, 对支持库进行单独测试也更容易。 社区里使用我们模块的人已经为我们提出了很多 Bug。 现在对 Node. js 来说最有用的工具也许是 Node 包管理器 npm。 使用 npm,我们能轻松使用其他程序员编写的库, 我们也可以很容易地和 Node.js 社区分享我们自己的模块。

InfoQ:你觉得 Node.js 现在还缺些什么、 需要添加进来呢?你认为它应该如何发展?

TJ(Express):我觉得应该继续保持原样, 为框架做越来越有影响的底层基础。它应该从“空白”开始, 不受开发人员的影响。

Guillermo(Socket.IO):HTTP 服务器对 SSL 的支持还不完整,还有很多 Bug。除此之外, 它最终是要让人们去用的,要考虑通用用法、修复 Bug, 继而实现最佳模式。

Matthew(Geddy):大家都在使用包管理器(NPM) ,所以希望在 NPM 稳定之后,我们能以一种简单的方式安装库、 为构建的项目指定依赖关系。

很多刚起步的项目都在尝试处理数据存储和持久化, 但还没有最佳解决方案。我们仍需要一个稳定的 ORM, 它能为关系型存储和非关系型存储同时提供通用的 API。

服务器端 JavaScript 还有很多尚未开始开发的需求, 所以我觉得生态系统会很自然地转去填补目前的这些空白。

Astro(node-xmpp):我特别想从 node- xmpp 中删除对 node-base64 的依赖。 暴露 Base64 编码 / 解码的补丁已经发布,但还没有合并进来。

我发现到处都在提 CommonJS。 这个项目旨在对跨多个 JavaScript 接口 / 框架的库进行标准化。他们已经实现了模块系统, NPM 也使用他们的 package.json 规范。 除 CommonJS 之外,恐怕不会有太多的共享模式, 因为相对很多其他的实现来说,Node. js 里的所有内容都必须是异步的。

对很多人来说,找到合适的 Web 框架也很有意思。

异步编程有时候非常麻烦,我明白开发人员有时候忽略回调引用, 是否只是想让控制流能更加直截了当一些。

Peteris 和 James(StackVM):每当我们想出一 些有潜力的 Node.js 新库,我们会自己开发并发布出来, 这样其他开发人员就不用浪费时间去重新发明轮子了。 其他很多程序员也都在这么做, 库的支持生态系统就会很自然地演进。Node. js 核心就是要尽可能小,由支持库来提供大量的功能, 对社区驱动的项目来说,这是一个分配工作负担、 鼓励参与的很好的方式,

InfoQ:你项目以后的路线图是怎样的?

TJ(Express):现在还是让 Express 保持精简。 对于那些适合项目的重点功能,我都会接受它们的新思路和补丁。 开发人员现在甚至可以把 Express 看成是“框架的框架”, 因为对那些更大型、偏向于自己使用的框架来说, 它本身就很容易成为构建块。 最后我要感谢 Ciaran 和 Aaron 的巨大贡献, 还有我的老板 Sencha 允许我和 Tim 回馈社区。 

Guillermo(Socket.IO):我现在正努力让 So cket.IO 尽可能地迅速、精简、易于测试。

Matthew(Geddy):Geddy 还有很多工作要做:

  1. ORM 查询 API
  2. 目前模型代码中的持久化部分是非常重要的。ORM 非常复杂, 任何既要和关系型存储交互, 又要和非关系型存储交互的内容都越来越难构建。

  3. 插件 API

    Geddy 需要一种简单的方式,去支持第三方构建的插件功能。

  4. 认证

    认证就是应该用插件去实现的绝好例子。

  5. 更好的模块化

    编写 Geddy 是为了提供一种集成的、“开箱即用”的体验, 让开发人员编写真实应用时不那么手忙脚乱。 但 Geddy 提供组件应该更容易选择和使用, 或者某个特定的部分能很容易地被其他内容替换。

  6. 除了简单的 EJS,还要支持其他的模板库

    人们喜欢用奇妙的东西,比如 Haml 或 Moustache。 Geddy 应该让大家能使用这些内容。

  7. 测试覆盖率

    Geddy 有大量针对路由器的测试, 还有一套针对模型和验证的测试套件,但其余代码还没有覆盖到。 Geddy 的代码需要进行重构、要更容易测试, 以便我们有更完整的覆盖率。

Astro(node-xmpp):我很高兴在发布项目之后, Github 上马上就有了关注者。除此之外, 我一直在期待一些实质性的贡献。

我自己的目标已经达到了,因为我只想完成 XML 解析和认证, 并不是在库的基础上实现所有特定的 XMPP XEP 规范。XMPP XEP 规范的实现就留给应用开发人员去完成吧。

Peteris 和 James(StackVM):短期内, 我们会侧重于添加更多的功能,还有性能优化。 以后我们很可能会关注硬件和可伸缩性。

InfoQ 上,你可以找到更多关于性能和可伸缩性、或 Java Script 的内容!

查看英文原文: Virtual Panel: The Node.js Ecosystem - Frameworks, Libraries and Best Practices


感谢崔康对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论