OSC 协同译者
英语书名:10 Node.js Best Practices: Enlightenment from the Node Gurus
校对:塞外, BigEcho, Tocy, 无若, 火星撞火星的魔法师, ismdeep
我曾在10 个基本功,2017 年成为更快的 Node 开发人员如是说了10个Node.js的基本功和控制技术。这首诗旁述的文档是在那此基础其内更进一步延展出的10个最差课堂教学,协助你将Node专业技能提升到捷伊层级。上面是责任编辑囊括的文档:
1.采用npmJAVA——停止采用bashJAVA,npmJAVA和Node能更快地组织机构JAVA。比如说,npm run build、start和test。当开发者考量新项目的这时候,npmJAVA或许是惟一值得称赞坚信的小东西。
2.采用env表达式——借助process.env.NODE_ENV,它可以增设为development或是production。这类架构也会使用这个表达式,所以请按惯例采用它。
3.认知该事件循环式——setImmediate()绝非立刻继续执行,nextTick()也不一定就是下两个。采用setImmediate()或是setTimeout()会将CPU专门化各项任务放到下两个该事件循环式周期性进行。
4.采用机能承继——在增容标识符以及认知蓝本承继或类的这时候,要防止采用过多忍耐力陷于一味的争辩。像了不起的NodeCOBOL们那般采用机能承继就好。
5.采用正确的名称——给该文起个有象征意义的中文名称。同时请千万别小写配置文件,并在需要的这时候加进连字符串。小写的文档名不能让人真的怪异,但可能在虚拟化时发生问题。
6.考量不采用JavaScript——可怜的ES6/7经过6年的会议商讨终于诞生的这时候,我们已经有更快的 JavaScript,CoffeScript。如果你愿意高效产出标识符,并且不想再纠结var/const/let、分号、class和其它主题,那就用CoffeeScript。
7.提供原生标识符——在采用转译器的项目中,直接提交原生标识符(构建结果)可以让你的项目不需要 构建直接运行。
8.采用gzip——唔!npm i compression -S和理性的日志——不要太多也千万别太依赖环境。npm i morgan -S。
9.扩大规模——从采用Node进行开发的第一天开始就应该考量集群和无状态服务。采用pm2或是strongloop的集群控制。
10.缓存请求——从你的Node服务榨取最大性能,把它们放到像 Nginx 这样的静态文件服务器后面,并像 Varnish Cache 和 DNS 那般对请求进行缓存。
上面我们依次来看看上面提到的每一条。
采用 NPM 脚本
现在npmJAVA几乎已经成为两个标准,它被用来进行构建、测试以及最重要的启动应用。这是两个Node开发人员遇到两个新Node项目的这时候首先要看的地方。有些人(1, 2, 3, 4)甚至已经抛弃了Grunt、Gulp,转用更低级更可依赖的npmJAVA。我完全能够认知他们的观点。考量到npmJAVA有前后钩子,你可以使它实现非常复杂的自动化:
通常在进行前端开发的这时候,你可能会运行两个或是更多的监控进程以实时重新构建标识符。比如说,两个 webpack进程,两个nodemon进程。因为第两个命令不能产生提示,你可以用&&来运行它们。不过有两个方便的模块,叫做concurrently,它能同时启动多个进程。
同时,应该在项目内安装命令行的开发工具,比如说 webpack、nodemon、gulp、Mocha等,以防止产生 冲突。你可以在bash/zsh的profile中指定像./node_modules/.bin/mocha这样的路径(PATH!):
采用环境表达式
在两个项目的早期阶段,借助环境表达式,可以确保不泄露敏感信息,并且能从一开始就正确构建标识符。而且,很多库和架构(我知道其确切的表达)会将信息放到 NODE_ENV 这样的环境表达式中修改。把它增设成 production。并把它增设你要的 MONGO_URI 和 API_KEY 的值。你可以创建两个 shell 文件(例如:start.sh),并且加进到 .gitignore:
Nodemon 也有两个配置文件,你可以增设你自己的环境表达式(例子):
认知该事件循环式
强大而聪明的该事件循环式之所以能让Node如此快速和高效是因为它充分借助原本浪费在等待输入和输出各项任务的所有的时间。 因此,Node非常适合于优化I/O专门化系统。
如果你需要继续执行这类CPU专门化(例如,计算、密码的哈希码或是数据压缩),那么除了为这些CPU各项任务启动捷伊进程之外,你可能想要探索如何使用setImmediate()或是setTimeout()来延期继续执行各项任务——它们回调函数中的标识符将在下两个该事件循环式周期性继续运行。 注意喽!nextTick()工作在同两个周期性,与字面含义相反。
这是一幅源自工作于该事件循环式上的Bert Belder的图。它非常清楚的展示了该事件循环式是如何工作的!
采用机能性承继
JavaScript支持蓝本承继,即这类对象从其它对象承继。ES6中也加入了 class 运算符。不过它明显比机能承继更复杂。多数Node大量指出后者更为简洁。它通过两个简单的函数工厂模式实现,不需要采用蓝本、new或是this。当你更新蓝本的这时候不能产生副作用(即导致所有实例改变)因为在机能性承继中每个对象自己有方法拷贝。
看看上面源自 TJ Holowaychuk 的标识符。TJ Holowaychuk 是两个天才,作品有 Express、Mocha、Connect、Superagent以及 其它很多Node模块。Express就采用机能性承继 (完整源标识符):
客观的说,核心Node模块采用了很多蓝本承继。如果你也采用这种模式,一定要搞清楚它如何运作。你可以看看这里的 JavaScript 承继模式。
采用正确的中文名称
这一点是显而易见的。好的名字具有文档的作用。你更喜欢哪两个?
如果只看 app.use(),我不知道 dexter 在干啥。如果采用更有象征意义的中文名称会怎么样:
同样的,配置文件也必须正确地反映其内部的标识符是做什么用的。看看Node的lib目录(GitHub 链接),这里所有标识符都与平台绑定,你会看到清楚明白的文件/模块中文名称(即使你对所有模块都不熟悉):
内部模块与标识符中的方法和变量一样,采用下划线标记(_debugger.js、_http_agent.js、_http_client.js)。这会让开发人员警觉:这是两个内部接口,如果你想采用它就得全靠自己——千万别因为它被重构甚至被删除而产生抱怨。
考量千万别采用JavaScript
嗯?你刚刚读对了吗?但是究竟是什么意思呢?是的。这是正确的。即使采用ES6和ES2016/ES7增加的两个机能,JavaScript仍然有它的quirk。除了JavaScript,还有很多其他可供您或您的团队通过极少增设中获益的选择。根据你的专业水平和应用程序的性质,你可能会选择更快的TypeScript或Flow提供强大打印机能。另一种极端情况,也存在像Elm和ClojureScript这种纯虚函数式语言。 CoffeeScript 是另两个了不起的和富有争议的测试选择。你也可以了解下Dart 2.0。
当你需要的仅仅是几个宏的话(宏允许采用构建你需要的语言),而不是两个完整的新语言,那么可考量下Sweet.js,它几乎是这么做的 – 允许你编写用于生成标识符的标识符。
如果你选了非JavaScript路径,请依然包含你所校对的标识符,因为一些开发人员可能不太了解你所采用的语言并正确地构建它。例如,VS Code是最大的TypeScript项目之一,也许在Angular 2之后,Code开始采用TypeScript来对Node的核心模块进行类型化。在VS Code repo(链接)的vscode/src/vs/base/node/中,你可以看到熟悉的模块中文名称,例如crypto、process等,但是都包含ts扩展名。在repo中还有其他ts后缀的文件。但是,他们还包括采用原生JavaScript标识符的vscode/build。
了解 Express 中间件
Express 是个了不起而且成熟的架构。它的光彩源自允许大量其它模块对其行为进行配置。这样说来,你需要知道常用的中件间以及如何采用它。为什么不看看我的 Express 作弊表。其中列有我两个主要的中间件。比如说,npm i compression -S 会因为减少反应而降低下载速度。logger(tiny)或logger(common)分别会提供更少(dev)或更多(prod)日志。
扩大规模
Node因为其非阻塞式I/O而在异步方面非常了不起,它只需要简间的标识符就能保持异步特性,因为就只有两个线程。这使得有机会早期,甚至在写第一行标识符的这时候,就开始扩大规模。Node 有核心 cluster 模块,它 让你在纵向扩展时不能遇到太多问题。不过,采用像 pm2 或是 StrongLoop 的 集群控制 这样的工具可能是更快的方法。
例如,上面演示如何采用 pm2:
然后你可以对同两个服务启动 4 个实例:
对于 Docker,pm2 版本2+ 提供了 pm2-docker。所以 Dockerfile 可以这样:
官方的 Alpine Linux pm2 映像在 Docker Hub。
缓存请求
这是一条DevOps最差课堂教学,它允许你从Node实例中获得更多的协助信息(你可以通过pm2或其他类似的获得更多,见上文)。方法是让Node服务器做app类似的请求、处理数据和继续执行业务逻辑,并将流量负载到另两个Web服务器(如Apache httpd或Nginx)的静态文件上。 再次,你可能采用Docker进行配置:
我喜欢采用Docker组合来配置多个容器(nginx、Node、Redis、MongoDB)。示例如下:
总结
在如今这个开源软件的时代,你没有借口不去学习那些已经开源并且可信的、测试过的源码。你不必在自己的圈子里得到这些(源码)。学无止境,并且我坚信很快我们就从我们将要经历的失败和成功中获得不同的且最好的练习。这是可以保证的。
最后我想写一写关于软件正在如何吞并这个世界以及JavaScript正在如何吞并软件的…它们和每年出现的标准一样的版本,数不胜数的npm模型,工具和会议…但是相反只要是我提过一句的我还是会完成的。
我发现好多人都在追赶下一代的新架构或是语言。这是典型的新鲜对象综合症。他们每周学习捷伊库以及每个月学习捷伊架构。他们强迫自己依赖Twitter、Reddit、Hacker News和JS Weekly。他们在JavaScript的世界里频繁采用这些来拖延(自己创造自己的小东西)。他们的公共GitHub历史是空空如也的。
学习捷伊小东西是好事情,但是千万别混淆了实际的“建筑原料”。那些事物、那些支付你薪水的才是实际的“建筑物”。停止过度的制造。你不是在制造下两个Facebook。(不论是)Promises vs。(还是)generator vs。异步等待对我来说都是有争议的,因为等到有人在讨论中回答了线程的问题的(这时候),我已经写好了我的回调(函数)(并且使用CoffeeScript来以比ES5/6/7快2倍的速度完成(各项任务))
最后,最好的练习就是课堂教学,最最好的就是去掌握最本质的(知识)。阅读源码,在标识符中尝试捷伊小东西并且最重要的就是你自己写大量的标识符。现在,在这个点上,停止阅读,去实际操作吧!
talent-aio —— 即时通讯架构