当我们学习 Node.js 时,我们在学习什么?

Posted 架构之心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当我们学习 Node.js 时,我们在学习什么?相关的知识,希望对你有一定的参考价值。

在写文章的最开头,我想引用一段我已经引用烂了的一段前同事的话,也是对于 Node.js 圈中近几年开始浮躁的风气的一种质疑。

大家都说学 Node.js 学 Node.js,到底是学它的什么呢?是学 javascript 这门语言,还是学 Node.js 的 API?还是学 Node.js 各种三方库?

正如问题所说,Node.js 其实就三块内容,一块是 JavaScript,也就是老生常谈的 ECMAScript;

另一部分是也就是它的 API;最后一部分也就是最不需要学的,也就是生态圈中的各种库。

表象之学

学 Node.js 的人大抵是两个方向过来的,一是前端同学,二是后端同学。

对于前端同学来学 Node.js 来说,对于他们最大的优势是 Node.js 使用了 ECMAScript,与他们的老本行一样一样的;

而对于后端同学来说,优势在于他们有后端的一整套体系思想,而对于 Node.js 的 API 看起来会更加好理解。

ECMAScript

ECMAScript 是 Node.js 的根基,也就是大家所熟知的 JavaScript。目前市面上使用地最多的其实还是 ES5,即使是前端同学在写 ES6,在经打包之后,通常编译成的还是 ES5 的代码——出于兼容考虑。

而对于 Node.js 来说,基本上的 ES6 语法都已支持,但是还遗留了一些小坑,如 let 的效率实际上没有 var 高等。

举个例子,在 Node.js 的一些源码中,很多的提交都是将 var 批量替换成  const,而少见批量将 var 替换成 let,比如这里。不过由于新版的 V8 中开启了 TurboFan,这效率就不一定了。

不过,哪怕是前端小伙伴们,也不一定能把 ECMAScript 给啃全咯。除了书中自有黄金屋之外,我在这里更推荐的是学习如何看 ECMAScript 规范。

ECMAScript 要入门,很简单,无非是 C-Style。稍微精髓点的就是原型与原型链那一套了。

不过现在 ES6 出来,大家习惯了 class 之后,兴许就把原型链给淡忘了。希望大家还是不忘本,这东西还是得拾起来。

但是一到比较偏僻的地方,就需要网上提问了。比如这些问题:

  1. 为什么 1 + undefined 结果是 NaN,而 1 + null 结果却是 1( https://www.zhihu.com/question/56007530/answer/147330933 )

  2. 关于两个 {} 的比较(如 ==!=<=>= 等)结果的真假值问题。( https://www.zhihu.com/question/56013048/answer/147328626 )

就结果来看,很多已经理解的人就不必吱声了,大多其他小伙伴要么是靠死记结果,要么就是上百度、知乎等地儿搜,搜出来还大多是你抄我我抄你的答案,剩下的小缕同学就干脆不知道结果了。

其实去 StackOverflow 等地查效果应该会更好,然而答案最直接的地方还数 ECMAScript 规范(https://www.ecma-international.org/)了。

其实在一看到这两个问题的时候,我也是不知道原因的,也信不过网上的大多答案解释。然后就上 ECMAScript 规范去追根溯源了。

首先第一个问题,它就是关于操作符 + 的一些定义,我们稍微检索一下,就能找到它的出处在 ES5 的(再早的版本我们就不追溯了)11.6.1 节(https://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1)中。

这一节的内容讲述的就是加号操作符的计算方法。将两个值先执行一个 ToPrimitive 操作,而对于这个操作,ECMAScript 规范中也原原本本给出了一张对照表。

1undefinednull 三个值经过 ToPrimitive 操作后一点都没变;接下去判断左右值是否有字符串,若没有,则将两个值再进行 ToNumber 操作进行相加。然后对于 ToNumber 操作,规范也原原本本给出了一张对照表。

当我们学习 Node.js 时,我们在学习什么?

从这张对照表看出来,undefined 的结果是 NaNnull 的结果是 +0,自然两个相加结果一个是 NaN 一个是 1 了。

第二个问题的结果也是类似,只要顺藤摸瓜,自然能在规范中找到相应的答案。其实什么原因不原因的,最后追溯到结果都是人(也就是委员会)制定出来的结果。

这里略微提醒一下,等值操作和大小比较操作分别在 ES5 的 11.9.3 节(https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3)和 11.8.5 节(https://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5)中。

所以本节中,我们说的就是要学好 JavaScript,在初步入门之后,借助 ECMAScript 规范加深自己对其的理解。

Node.js API

讲完 ECMAScript,我们接下来再要讲讲的就是 Node.js 内置的 API 了。大家都知道,Node.js 就是靠着 V8 来作为 JavaScript 的运行引擎,libuv 作为事件循环的框架,然后上面像胶水一样黏上一堆易用的 API 就成了。

所以这些 API 就是大家入门 Node.js 的时候最先遇到的必修课了。

相信很多人跟我一样,第一次接触 Node.js 的时候都是这样的几行代码:

当我们学习 Node.js 时,我们在学习什么?

一开始学的人可能会觉得很神奇,其实现在看来无非就是 Node.js 内置的 http 模块中的一些 API,如 http.createServer(callback) 等。

要说这些 API 去哪学,其实用不着看什么网上的教程啊什么东西,所有的这些原原本本都在 Node.js 的文档之内。

如 6.x 的 Node.js 文档就可以看(https://nodejs.org/dist/latest-v6.x/docs/api/),里面无非三十几个模块,而且内容都十分简单且实用。

例如 http 和 https 模块就是我们最常用的用于创建我们 HTTP(S) 服务器以及用于 HTTP(S) 客户端请求的模块,虽然现在大家用于线上开发大多都用了类似 Express、Koa 等框架或者 Request 这类库,但是实际上他们的最底层用的还是 Node.js 的这些模块这些 API。

API 没多少要学的,就算真的从头到尾看一遍,甚至也花不了一天(前提是对其中的各种前置知识了解)。大不了在一开始学的时候先过一遍,拣常见的学熟络了,然后在日常开发中再积攒肌肉记忆,就差不多了。

为什么这么说呢,因为哪怕是你真的死记硬背背下来了,下个版本说不定得变。举个例子来说,dns.setServer() 这个函数,自 Node.js 8.2.0 起,就支持了自定义 DNS 服务器端口,如:

dns.setServers([ "103.238.225.181:666" ]);

这个函数的新特性自 Issue#7903 (https://github.com/nodejs/node/issues/7903)提出并在 PR#13723 (https://github.com/nodejs/node/pull/13723)中被实现并且在 8.2.0 版本中正式发布。

除此之外,在 Node.js 的弃置 API 中也列了一堆在各种版本中被弃用的 API,就我以前用最多的就是 fs.exists() 函数,但是在 1.0.0 中就被标记为弃用了,只是目前来说还没有下架而已——指不定哪天就下架了呢。

这些被弃用的 API 也在 Node.js 的文档(https://nodejs.org/dist/latest-v8.x/docs/api/deprecations.html中被列了出来。

总之在 Node.js 的快速迭代中,各种事情都是有可能的。在维护者和贡献者的提交中,分为 Patch 提交、SEMVER-MINOR 和 SEMVER-MAJOR 三类提交,其中 SEMVER-MINOR 是中间的版本号更新,即非 Break 但是有功能改动、更新的提交。

而 SEMVER-MAJOR 指的是那类 SEMVER-MAJOR 提交,如下架 API 就是一类 SEMVER-MAJOR 的提交。

由此可见,学 Node.js 的 API 时,我们大多只需要记住并熟练使用常用的一些即可,其余的就仰仗实时翻阅 Node.js 文档,以及关注 Node.js 新版本发布时候的 Changelog,尤其是那些 Notable changes(https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V8.md#notable-changes-1)

再下一步就可以有事没事去看看 Node.js 源码仓库中的 PR 了,参与讨论讨论也是不错的选择,还能参与到 Node.js 的贡献当中来。

Node.js 生态圈

个人认为,这是 Node.js 中最不需要学的一块内容了。

怎么说呢,Node.js 的生态圈非常庞大,其生态圈中的库质量参差不齐。有有着很大用户群的 Express、Koa 等,也有着闹着玩的 five 这类库。

无论是什么,总之根源还是在于检索加上看文档以及造轮子。

首先第一步检索,无论是谷歌、NPM 自带的搜索引擎,还是自己脑海里的人肉搜索库,都是检索的根基所在。

例如我们如果要写一个 Web 应用,首先就是想到要一个 Web 框架,然后脑子里应该首先冒出 Express、Koa 等既是框架又算不上框架的 Web 库,或者再小众点就是 hapi、egg 等框架;

如果觉得自己想另辟蹊径,找找看有没有什么更小众能体现自己逼格的东西,就可以上搜索引擎搜了,比如 Node.js Web Framework 等关键字;

最后,如果觉得还不过瘾,那就自己造哇,比如我们团队就用的是自己造的 Akyuu.js 框架(https://github.com/akyuujs/akyuu 框架还在沉淀中,文档还未来得及写)

再比如,我们在写 Web 应用的时候,要用 md5 给密码进行简易加密。其中一个办法是使用 Node.js 的 crypto 模块,但是写起来也略冗长,还有个办法就是去 NPM 上搜搜看有什么好的包可以用咯。

输入 md5 关键字,我们能看到好多可以用的包。可以拣一两个看着顺眼的用,如:

  • md5

  • blueimp-md5

  • md5.js

  • apache-md5

至于用嘛,到自己拣好的包里面看看文档就好用了。所以这就是我所说的,Node.js 生态圈中的包,看文档就够了。

大不了看官方出的教程,例如 Express 的官网(http://expressjs.com/)。看这些东西要远好于自己去百度搜索抄来抄去的教程。

还有一类库,是通过其它的库被包装而成的,那在看文档之前,可能要先去了解一下原库的一些内容。

举个例子来说,gm 这个包是 Node.js 中用于图像处理的包,其原理是通过执行 GraphicsMagick 命令的形式加上管道来进行处理的。

所以要用 gm 的话,还需要事先去了解 GraphicsMagick 的一些用法,尤其是一些参数等等。

还有就是像 tensorflow2 这种包,相信大家都想到了,用它之前还得先去了解 TensorFlow。

最后就是,当大家找不到想要的包的时候,就轮到自己造轮子,反哺 Node.js 生态圈了。

比如我就曾经实现了一套 Node.js 中使用的 ORM 库,唤作 Toshihiko,与市面上常见的 ORM 如 Sequelize 等大相径庭,主张简约和性能,并目前在我厂广泛应用。

其它更多的我参与或者我发起的一些 Node.js 生态圈的贡献,可以查看我的 me 仓库。

所以本节中我们所说的,学习 Node.js 生态圈,无非就是学习如何检索生态圈的内容、好好过滤并去其糟普取其精华,然后还是很重要一点就是学习如何查看文档,在有前置知识的库面前要先学习它的前置知识。

包与模块机制

Node.js 中的包与模块机制都是借鉴了 CommonJS 的模块规范和包规范。关于这一块我曾经开了一场知乎 Live 详细讲解——足足讲了三四个小时还是虎头蛇尾。

这么长的一块内容还是值得一学的。如果大家偷个懒,也可以看看我的知乎 Live——《深入了解 Node.js 包与模块机制》(https://www.zhihu.com/lives/842742839304667136)

异步之旅

很多从后端转过来学 Node.js 的同学中,一开始入门最大的障碍就是它的异步非常令人烦恼,尤其是回调地狱。

就连我当年一开始学习 Node.js 的时候,也非常不适应。在什么也不懂的时候硬生生搞了个自己习惯的框架,把里面的异步操作通过 fibers 硬生生转成了同步的写法。现在回过头来想想,还是太年轻了。

习惯 Node.js 中的异步,个人认为是非常有必要的。

Callback

回调函数是 Node.js 中的基础所在,大量的内置 API 都是通过回调函数来触发事件返回结果的,如 fs、http 中的一堆堆函数,以及目前市面上大部分的三方库。

不过这货最让大家烦恼的就是传说中的回调地狱了。

但是我个人认为这都不是事儿,通过 async 这个包就能比较大程度地化解了,而且它还有非常多地流程控制的函数,形如 eachLimitwaterfallparallelauto 等等,在 async 中就能非常简单地实现了一堆的流程。

可以说 Callback 正是 Node.js 已至 JavaScript 的精髓所在,连响马大大都在微博中挺 Callback 了。

callback 虽然慢,但是并不太慢。而为了解决 callback hell 引入的流程框架,一个更比一个慢。导致使用这些框架的应用,性能直线下滑 50-100 倍。【没错,说的就是 async】 (指的是 async 语法)

把 callback 玩到这么精致,也就是 JavaScript 了。

以及在交流过程中说的话:

如果没得选(指 fibjs),肯定是用 callback。

这玩意儿,主要就是要熟练,和思维转换。当大家熟悉了 Node.js 中事件循环的原理后,再回过头来看 Callback,其实也没那么难了。

当再配合上 async 这个包,照样能写出非常优雅的代码。

Promise 与 yield

Promise 是另一套异步之旅中的概念。相信当下入门的 Noder 们应该会比较了解 Promise。而且当下的 Node.js 中已经加入了内置的 Promise 支持。

而且实际上在学习 Node.js 中,Promise 相较于 Callback 来说是更易学、易于掌控的,这也是为什么 Promise 更被大众所接受。

而 yield 来说,这个概念对于很多其它语言转过来的后端同学不会陌生,如 python 就有这个概念。它主要配合菊花函数(即生成器函数)使用。

而且 Koa 框架中的异步大多使用 yield 来完成。

实际上这一块来说,仍然是前面章节讲到的 ECMAScript 的一块子内容,所以还是归于要好好学习 ECMAScript。

async 与 await

这是 Node.js 8 中推出的另一套异步解决方案。在先前的 7 版本中,其实已经加入了该方案的支持,只不过没加入默认支持而已。

只不过目前而言,实际上 async 与 await 仍然在 ECMAScript 的草案(https://tc39.github.io/ecmascript-asyncawait/)之中,Node.js 中提前把它弄起来了。

如果是 C# 转过来开发的童鞋应该对该函数不陌生。话说回来,实际上这一块也算是 ECMAScript 学习的子内容。

深入学习

当大家学会了 Node.js 中《表象之学》一小章的内容之后,可以说是入门了 Node.js 了,这个时候基本上对于平常的 Node.js 开发已经游刃有余了。甚至可以就着网上的教程,开始各种 Web 应用的开发了。

不过本文不是教大家如何看教程的,而是别的内容。

表象之学的内容通常有点编程基础的人来说都易学,前端同学在语言上会更占便宜一些。如果前端的同学们想开始企业级的线上应用,下面的内容才是应该深入学习的。

虽然看起来下面的内容与 Node.js 无甚关系,但是作为一个合格的开发来说,更深入的一个层次,就是网上流传甚广的一句话了。

忘记语言。(虽然 php 是最好的语言 ヘ|・∀・|ノ*~●)

数据库

如果仅把 Node.js 当做玩具来看待,随便三下五除二学一下数据库就可以了。

我曾经接手过一个 Node.js 的外包项目二期的开发,非常痛苦。数据库完全是乱设计,看起来更像是被各种劣质教程害了的那种。

对于学习新兴的 NoSQL 来说,还是推荐顺带扎扎 SQL 的相关底子,如 mysql

记得大学的时候我们用的数据库书是自己本校老师写的,里面各种原理还是受益匪浅的,虽然说现在很多地方都忘得差不多了,但是学过之后脑子里有个印象,下次提起的时候就又会恍然大悟了。

例如 SQL 的检索语句的语法树、索引相关内容等等。

以及数据量到了一定程度的时候,分表、分库、读写分离等等内容。虽然很多都是 DBA 给的建议,但是也有很多公司是并不具 DBA 岗位的,很多时候都是要靠自己。

不过在线上各种应用当中,大多的 Node.js 程序都是使用了 ORM 来搞定,所以很多时候用不着大家亲自写 SQL 语句,而是直接使用 ORM 里面的各种函数。

本节说的数据库学习中,更多还是需要学习如何更好地设计数据库,弄更好的各种解决方案等等。

在大家扎好了 SQL 的底子之后,也可以开始尝试着各种 NoSQL 了。目前比较火的就是 MongoDB,并且某种意义上,Redis 这类也是属于 NoSQL。

后端思想以及代码抽象

要学习 Node.js,若想做后端开发的话,后端思想以及代码抽象是非常重要的。

关于后端思想,其实是个很虚很悬的东西。它的整个学习体系中包括但不局限于这些内容:

  • 安全

  • 网络编程

  • 算法与数据结构

  • 服务化

  • 数据库

其中数据库在前面一节中我们就提到了,是一个非常重要的后端组成部分。安全、网络编程和算法与数据结构其实在前端中也可以有体现,但是占比还是比较少,甚至很多前端同学也还没思考过这些问题。

而对于要学习 Node.js 的童鞋来说,还是推荐学习这些关于后端的思维。

做接口、方案、编码的时候,首先要考虑到设计是否安全,其次是性能以及服务器压力等。后端是一个应用最后的防线,一定要严把关。

在前端的安全性做得再好,一旦有人绕过前端直接给后端发请求,攻击就直勾勾发到后端去了。

大多的后端转 Node.js 的同学在这一方面比前端同学占便宜,因为思维上大多会惯性地考虑这些点,而前端同学转过来的时候往往会栽在这些地方,设计接口、方案的时候不够「后端化」。

所以在学习 Node.js 的时候,学习后端的思维是非常重要的。

关于后端思维,还有很重要的一点就是代码层面的抽象。举个简单的例子,当前很多前端的框架都是抽象成 MVVM,而后端当下最通用的抽象就是 MVC。

我在前面讲过一句话,说 Express 等既是框架又不是框架,就是因为它们没有一个非常好的层次抽象,一千个人写出来的应用有一千个模样。

这导致了还是我说的之前接手的一个项目,代码根本没有抽象,所有的 SQL 代码都是硬生生写到各种路由逻辑当中。

在一个企业的项目当中,这种抽象是非常必要的,一段解耦的代码会非常好维护,使得接盘侠会特别爽。

其实不只是 MVC 的抽象,抽象还分很多种方式。如很多面向过程的代码,在稍加修饰之后,就能抽象成优雅面向对象的代码(当然,在 FP 中另当别论,不过本文讲的是跟 Node.js 相关的学习,所以我还是比较推崇面向对象的抽象方法)

关于抽象还有一个不得不提的就是设计模式,这也是一个合格的程序员(Node.js 程序员当然也是程序员中的一类)可能所需要了解的内容。

尤其是其中的适配器模式、工厂模式、单例模式等,在日常中大家也经常会用到。

那么,为什么说算法和数据结构重要呢?可能很多时候大家在平时写代码的时候觉得算法或者数据结构离自己都挺远的。实际上你可能在不知不觉中就用到它了。

Redis 中大家用到的 Set 就是一种常见的数据结构,只不过 Redis 都帮大家给包裹好了,包括查询的操作,最终通过网络给返回结果给大家。

再比如,我在我以前写过一篇文章《我为什么要使用哈希》(https://xcoder.in/2015/10/16/why-i-use-hash/)中就介绍了哈希的一些妙用。其中文章中的「报告图问题」和「唯一主键问题」两个问题都是我在实际 Node.js 工作中进行的使用哈希做的一些事情。

这跟后端的思想也都紧密联系在了一起,例如为了节省空间的去冗余,同时由于减少了记录数也提高了查询的效率;又例如由于有时候考虑到不使用自增主键的情况,就可能要通过哈希来生成一个。

这一块应该是 Node.js 乃至所有程序员需要学习的最重要的一块内容了。内容非常多,也不是三言两语能讲完的,就我自己而言也还只是在山脚下往上看,只是希望能给大家指一条路,与诸君共勉。

其它领域

很多时候,当我们做项目在技术选型,除了说生态圈中哪个技术更成熟以外,性能优劣以外,还有一个考虑的重点是,实施项目开发者的趁手兵器是什么。

论 Web 开发,Java 无疑是更成熟的方案,但是我就是不会 Java,我就是会 Node.js,那如果项目让我来做,我肯定会选 Node.js——除非有方面遇到了瓶颈。

那么其它领域也一样,作为一个能在本地跑的运行时(而不是像前端 JavaScript 一样只能寄宿在浏览器当中),理论上 Node.js 可以做其它同类语言都能做的事。如科学计算、人工智能等等,无非是领域的生态圈强不强。

比如还是我们先前提到的 tensorflow2 这个包,就让 Node.js 在深度学习的领域中有了可能性。而对于硬件开发,同样的,我们能用树莓派中装上一个 Node.js 来驱动我们用该派组装的一部小车。

在前端领域中,实际上 Node.js 做的事情非常有限,毕竟它不能在浏览器中跑——它主要做的事情是为前端各种生态圈提供命令行工具,以及可以使用类似 nw.js 之类的东西来写桌面 GUI 应用。

说前端生态圈的命令行工具,实际上用什么语言写也都一样,只不过还是我的那句话,前端生态的开发者对 JavaScript 更熟悉,用 Node.js 更为合适,要知道,在很早之前 JavaScript 代码压缩等活也都是通过其它语言写的脚本或者工具实现的,如 YUICompressor。

所以对于 Node.js 在其它领域中的应用,我的推荐是大家先去了解该领域的各种基础知识,语言只是工具,换了谁都一样,包括后端。

最终大家用的时候看的主要还是熟练度,也就是开发成本和开发效率——毕竟除非是真的需要压价性能到极致的时候,通常性能不会成为我们选型的瓶颈。

就比如我们在做网关开发的时候(这里有我上次分享的一个 Slide),反向代理层之间上了非常成熟的 OpenResty,而与之交互的请求解析服务,我们毫不犹豫地选择了我们最熟悉的 Node.js,如果这个项目交给我们公司的 Java 团队来做,我相信他们也会毫不犹豫地选择 Java。

源码剖析

前面讲了各种 Node.js 学习时,我们所需要关注的点。后端思想这一块由于太大,可以贯穿大家的整个程序员生涯(哪怕是只想拿 Node.js 来写写命令行工具,或者 GUI 应用,学习这一块内容也是无害的)

剩下的其它点应该是不难的,等大家熟悉了这些点、学习得差不多之后,就可以开始剖析 Node.js 的源码了。

网上不乏 Node.js 源码的剖析文章,我这里也介绍一些比较好的剖析方法。由于文章篇幅原因,我这里只介绍方法,不做详细剖析。

首先 V8 是 Node.js 的根本,所以希望大家在剖析之前,能了解 V8 的一些基本内容,使大家在阅读 Node.js 的代码时不至于太累。

这里有一篇《Embedder’s Guide》(https://github.com/v8/v8/wiki/Embedder's-Guide),是关于 V8 的基础,如句柄、句柄作用域等基础概念。

其次是 libuv,研读 libuv 文档会让我们在理解 Node.js 中一些异步代码会更容易一些。

不过这一切都需要我们有一定的 C 以及 C++ 的基础,相信这对我们好奇的程序员们并没有什么特别大的难度。

在有了这两块的基础后,我们有两个方向的阅读方法。

其一,从入口文件开始看,开始理解各种源码是如何整合进入 Node.js 的。C++ 的入口文件就是 main 函数的那个文件,从该文件中追根溯源进去,一步一步剥洋葱一样看,在遇到比较难以理解的地方的时候不一定要完全搞懂,挑关键字和语义来阅读即可——毕竟 Node.js 的函数很大程度上都是语义化的;

JavaScript 的入口文件则是 lib/internal/bootstrap_node.js 文件,这一点其实在剥洋葱阅读 C++ 源码的时候就会发现,在 Node.js 初始化一定阶段的时候会执行这个文件,完成 JavaScript 环境的初始化。

其二,从胶水内置库开始看。当我们遇到一些问题,如 http 某个函数的实现原理的时候,我们就应该直接跑到 lib/http.js 开始阅读,在回溯其依赖的各种函数的时候,按照自己的需求去探索函数栈的深度。

在遇到 process.binding() 函数的时候,要根据其获取的内容,对应到 C++ 代码中的相应文件,如 process.binding('util') 对应的就是:

https://github.com/nodejs/node/blob/v8.2.0/src/node_util.cc#L236 这个文件。

掌握了这两种阅读方式,即使不是太了解 V8 的 API 和各种概念以及 libuv 的各种概念,也能比较轻松地阅读 Node.js 的源码了。

但是如果需要深入阅读理解 Node.js 源码的话,还是推荐大家去了解一下关于 V8 和 libuv 的一些概念。

在阅读代码的时候,大家也可以动手尝试修改一下相应的代码,以验证自己的理解是否正确。

这个时候就可以把 Node.js 源码仓库克隆到自己本地,然后可以着手修改一些内容并在编译之后执行一下,看看自己修改的地方是否如自己预期所示。

克隆编译 Node.js 的步骤还是比较简单的,如果是 *nix 下的用户,可以这么搞:

其中 <核数> 是你的 CPU 核数,即一个数字,如 make -j8

如果你有其它的疑问或者你是 Windows 下的开发者的话,可以自行阅读 Node.js 的构建文档(https://github.com/nodejs/node/blob/master/BUILDING.md)以获取更多信息。

小结

本文主要给大家介绍了当我们在学习 Node.js 的时候,推荐的正确学习姿势,防止大家误入歧途,光学习了最简单的表象内容,而忽略了学习一门后端语言更深一层次的体系。

其实在「深入学习」一节中,已经脱离了语言的范畴,而且事实上在实际工作中,语言反而是次要的内容,在开发经验中学习、总结、抽象出一套体系才是核心的思想。

最后再理一遍本文推荐大家在学习 Node.js 的时候比较舒适的一条路线吧。

首先走平地入门的时候,ECMAScript 是根基,在停留在表象语法的阶段上,可以更深一层次地去扒一些规范中约定的内容,如各种操作符在内部的流程是怎么样的;

在根基扎实的情况下入门 Node.js 是最好的,然后开始阅读其 API 文档,内容较浅,主要是快速入门如何使用它的基本 API 以供可以快速开发一些东西;

在熟悉 Node.js 内置 API 的同时,要了解它的生态圈,检索和阅读文档的能力是非常必要的,在生态圈无法满足自身的情况下,一种进阶的做法就是自己提供轮子。

在走这一条线路的时候,其它语言转过来的开发者可能会踩到一些异步的坑。

哪怕平时不使用 Callback 而是去使用 Promise 等东西,贯彻 Callback 的思想还是比较有必要的——不要忘本,毕竟这才是 Node.js 的精髓所在,而其它内容都是别的语言中借鉴过来的,很多别的语言转过来的开发者会感到比较亲切。

在入门之后,大家需要关注的点要从 Node.js 语言本身移开,关注后端开发的一整套体系。当然也不是凭空关注的,而是结合 Node.js 自身的特性,摸索一条适合它的体系。

正如「中国特色社会主义理论体系」一般,再怎么中国特色它也是社会主义,大家需要学习的是弄出一套「Node.js 特色后端理论体系」。

但是其根本不变,Node.js 特色再怎么浓厚它还是后端体系,如结合 Node.js 开发的方式,搞出 Express 这类基于中间件的 Web 框架,但是安全、性能、结构分层还是非常有必要的。

还有一个重点就是数据库需要好好学,而不是简简单单地 CURD 会用即可——不然很多公司要 DBA 干嘛?哪怕我们不去抢 DBA 的饭碗,我们也不能对性能优化、表的设计一无所知随手一搞。

而脱开后端领域来说,实际上只要你乐意,Node.js 也可以做任何领域的事情,只不过是是否真的适合和是否趁手而已,摆正心态很重要。

学习用 Node.js 快速出原型也是一个不错的选择,例如深度学习的领域。

万丈高楼平地起,在我们深入学习一整套体系的时候,可以根据自身的能力,开始尝试阅读 Node.js 源码,理解它究竟是个怎么样的东西——其实它就是一个胶水层,V8 和 libuv 胶上一堆易用的 API。

最后,太极生两仪,两仪生四象,四象生八卦,八卦生万物。Node.js 就是万物中的一个,而整个编程界可以比作太极,我们从万物开始学,最后都需要归宗到太极当中去——当我们在学习 Node.js,我们其实就是在学编程,不要把自己局限住了。

当大家阅读完这篇文章后,对我的疑问不是局限于 Node.js 语法如何,异步的时候到底采用什么方案比较好的时候,我想我的文章思想才算是真正传递给各位开发者了。

阅读原文」查看本场Chat交流实录

以上是关于当我们学习 Node.js 时,我们在学习什么?的主要内容,如果未能解决你的问题,请参考以下文章

node.js学习

Node.js 学习一 第一个Node.js应用--Hello World!

「Node学习笔记」浅谈Node.js读写xlsx文件

node 学习

Node.js学习四 Node.js回调函数

从javascript获取和从node.js获取节点,有啥区别[关闭]