2015年9月9日,Node.js 重装上阵。社区在经过大半年的分裂,终于放出首个 Node.js 与 io.js 的融合版本——Node.js 4.0.0 版本。

Node.js 4.0.0 首次将 Node.js 和 io.js 项目的代码库融合到了一起,所以这次发布不仅包含所有 io.js 对 Node.js 作出的改进,也包含 Node.js 的 0.12 中的所有后续新增功能,而这些功能之前 io.js 的用户是享受不到的,例如朴老师之前就为 Node.js 提交了很多补丁,但 io.js 小于 4 的版本的用户是享受不到的。

站在今天,要开始开发一个新的 Node.js 项目,请用 Node.js 4.0.0。因为 4.0.0 是 Node.js 的未来,它才是真正的 “1.0”。

io.js 的历史使命已经完成

最初,io.js 是从 Node.js 分支出来的一个分叉项目。自从今年年初(2015年),Joyent 公司就将 Node.js 项目转手给了 io.js 社区,而这个社区的活跃程度超乎人们的想象,不到一年的功夫他为 Node.js 吸引到了来自全世界的百余名为之贡献核心代码的新开发者。年中前后,舆论认为,分道扬镳并不符合大家的共同利益,一个囊括了 io.js 和 Node.js 的所有功能的合并版 Node.js 4.0.0 呼之欲出。

io.js 的历史使命已经完成,大家也算是重新回到了正途。真是合久必分,分久必合!

4.0.0 是真正的 “1.0”

但是,考虑到上个 Node.js 的版本号才到 0.12.x,为什么版本号会上升的这么快以至于直接到了 4.0.0 呢?

这是因为,4.0.0 的前身 io.js 项目采用的是语义化版本编号法(semver),亦即<主要>.<次要>.<补丁>。而以前 joyent 公司的版本编号方法采用的是奇偶编号法。而这次合并之后,整个项目都将采用语义化版本编号法。历史上,io.js 从主项目分裂出来后不久,便发布了第一个主要版本号,1.0。

此次发布是为了防止与后续 Node.js 的 0.X 维护计划发生版本碰撞,同时避免与任何现有的 io.js 版本号发生碰撞,才决定将融合的版本号编号为 4.0.0。之后的版本也将沿用<主要>.<次要>.<补丁>编号法。

3.x 曾是 4.x 的试验场

当 io.js 首次发布的时候,它就将其内的 v8 引擎升级到了最新版本,而当时 Node.js 的 v8 已经好几年没升级了。伴随着 v8 的升级,一个新的 nan 版本也随之发布。

io.js 随后一直紧跟 v8 更新的步伐,可不幸的是,io.js v3 中包含的 v8 的变化实在是太大了,以至于不单一个新的 nan 必需随之升级,连 nan 中的 API 本身也要随着变化,要求所有 C++ 模块的代码也必须进行修改。

io.js 的维护者知道这是一个很大的变化,而且 C++ 模块的作者需要一些时间来追赶 io.js v3 中引入的变化。所以在 v4 之前的 v3 发布的几周内,已经开始鼓励模块的作者对新版本进行升级和测试,以对抗版本升级带来的模块不可用问题。

这次,虽然 Node.js v4 将包含一个更加高版本的 v8,但已经受到了 nan 的当前版本的支持。这意味着,谁升级了 nan 跟上了 io.js v3 的步伐,谁就自动跟上了 Node.js v4 的升级步伐。所以 3.x 其实是 4.x 的试验场。

三大内部依赖的版本升级

冰冻三尺非一日之寒,Node.js 是在三个重要的依赖项目之上建立起来的,亦即 v8、libuv、npm。这些项目都是由其他外部团队独立维护的,Node.js 只是将他们的源代码复制过来,放到自己的项目中加以利用。为了享受这些依赖的上游新版本带来的新功能,Node.js 需要不断跟上他们的版本。

当年创建 io.js 项目的一个原因就是 Node.js 的长线而难以预测的发布周期,相比于原 Joyent 公司的 Node.js 0.12.7 , io.js 项目对依赖的跟进速度要快得多。Node.js 4.0.0 则将这些外部依赖的推进到了几乎是最先进的版本,见下表。


Node.js 4.0.0原 Joyent 公司的 Node.js 0.12.7
内含 v8 版本4.5.103 (2015-07-08)3.28.71 (2014-08-12)
内含 libuv 版本1.7.3 (2015-08-28)1.6.1 (2015-06-06)
内含 npm 版本2.14.2 (2015-08-27)2.11.3 (2015-06-11)

Node.js 4.0.0 可以让您享受最尖端的技术,保持项目的先进性。其中对 v8 的升级几乎做到了与 Chromium / Google Chrome 同步,达到了 4.5.x,它提供了很多新的语言功能。ECMA-262 是 JavaScript 语言规范的最新版本,而且好多新特性数都是开箱即用的。这些新特性包括:

  • classes - 各种 ‘类’,再也无需用 CoffeeScript 的语法糖写类了

  • typed arrays - 类型数组

  • generators - 未来的.js 代码中将有无数生成器,不学一点就看不懂 JS 代码了哦

  • collections - 集合、映射、弱集合、弱映射

  • arrow functions - 箭向函数

  • block scoping - 使用 let 、const 作用域,块辖域

  • template strings - 模板字串

  • promises - 用标准化了的方法进行延迟和异步计算

  • symbols - 唯一的、不可修改的数据

物联网

物联网开发者们也会对 Node.js 4.0.0 感到高兴,因为它将对 ARM 平台的支持扩展到了 ARMv6、ARMv7、以及最新的 64 位 ARMv8 处理器。

模块作者更应重视

上文提到,3.x 曾是 4.x 的试验场,这需要引起 C++ 模块作者的重视,但受影响的不光是 C++ 模块。

从历史上看,在一次 Node.js 版本的发生升级时,大多数的 C++ 模块开发作者只是简单地升级自己的 nan 的版本到支持 Node.js 的最新版本的那一个。但不幸的是,模块也依赖于其他模块,问题没那么简单:存在模块依赖的模块、存在模块依赖的模块依赖的模块、存在模块依赖的模块依赖的模块等等。这些深层依赖关系链意味着,升级模块不是那么简单,很可能需要相当多的时间来协调好上下游代码的升级节奏。

C++ 模块有多少呢?现在不到 600 个模块是直接依赖于 nan 的,但如果你计算一下依赖于这约 600 个模块的其他模块的数量,你会发现数量一下子上升到了约三万多个。换句话说,间接依赖于 nan 的模块数量约有三万多个,受升级影响可能无法正常工作的模块约有三万多个。

这是个庞大的工程,这是个协作的工程,这是属于每个社区成员的工程。让我们大家携手,多多提交补丁,尽快让整个 npm 社区的模块生态系统完成升级。

升级看点

这次升级的改动是建立在 v3.x 代码基之上的,关于 2.5.0 - 3.0.0 的改动请见我之前发表的《io.js 2.5.0 - 3.0.0 升级看点及社区动态》:

https://cnodejs.org/topic/55c1fb135965fe2c74f477f8

如果您是从 0.12.x 升级过来的,必须同时补上 v3.x、v2.x、v1.x 这三课。

Node.js 4.0 相对于 v3.x 最值得关注的改进记录包括:

  • child_process: ChildProcess.prototype.send() 和 process.send() 跨平台的异步操作作为一个可选的回调参数,可在消息发送时候调用。例如 .send(message [, sendHandle][, callback])

  • node: 将 “io.js” 代码重命名为 “Node.js”

  • node-gyp: 该版本绑定了一个更新版的 node-gyp 支持所有版本的 Node.js 和 io.js。

  • npm: 版本从 2.13.3 更新到 2.14.2, 包含一个安全更新

  • timers: 提示定时器的性能,和一些小 bug 修复

  • util: util.is*() 函数被废弃,文档中已经注明废弃。建议用户寻找更可靠的替代方案

  • v8: 版本从 4.4.63.30 升级到 4.5.103.30

  • 实现新的 TypedArray 原型方法: copyWithin(), every(), fill(), filter(), find(),findIndex(), forEach(), indexOf(), join(), lastIndexOf(), map(), reduce(),reduceRight(), reverse(), slice(), some(), sort()

  • 实现新的 TypedArray.from() 和 TypedArray.of() 函数

  • 实现 arrow 函数