在这篇中,笔者会列出 2017 年成为更好 Node 开发者的技巧的大纲。这些技巧一部分是在具体实践中总结得出的,一部分借鉴了 Node 和 npm 优秀模块开发者的经验。

注意: 这篇文章之前的标题是 “来自平台大神的最佳实践分享”。文章内容是经过实际的测试和试验写出,但并非 2017 年最新技巧。 虽然,Node 大神分享的最佳经典实践在 2017 年,2018 年甚至 2019 年都会受用,但一些尖端功能,像 async/await, promises 并没有涵盖在内。因为这些新特性不在 Node 核心代码中,也不如 npm 和 Express 流行。文章第二部分,我将介绍此文章的性质。
我开始作为全职Node开发是在2012年,当我加入了Storify公司。 从那时起,我从没有回头或者觉得挂念Python,Ruby,Java和PHP——这些贯穿我之前十年web开发工作的语言。
Storify对我来说是一份有趣的工作,因为不像大多数公司, Storify所有的项目运行(也许今后依旧)都是使用Javascript。你看,大多数公司,尤其是大公司如贝宝(PayPal)、沃尔玛(Walmart)、或第一资本(Capital One),只是使用Node作为他们堆栈的某部分。通常他们使用它作为API途径或一个业务流程层。这也是不错的,但是对于一个软件工程师来说,没有什么比完全沉浸在一个Node环境中更棒的了。
我这篇博客中,我会列出 2017 年成为更好 Node 开发者的技巧的大纲。这些技巧一部分是我在具体实践中总结得出的,一部分借鉴了 Node 和 npm 优秀模块开发者的经验。主要内容如下:

下面,让我们对每项内容都进行一下了解吧~
避免复杂性
var module = require('module') module.wrapper[0] += '"use strict";' Object.freeze(module.wrap)
那么,为什么要避免复杂性呢美国海军传说中,有一句很著名的话:化繁为简,返璞归真(或理解为“编码的方式简单点,傻蛋!”)事实证明,人类大脑一次只能记住 5 项至 7项的内容,这就是此处要求简单的原因。
缩小代码模块,有利于你和开发者更好地理解代码,你也能更好地进行测试。参考以下示例:
app.use(function(req, res, next) { if (req.session.admin === true) return next() else return next(new Error('Not authorized')) }, function(req, res, next) { req.db = db next() })
或如下代码:
const auth = require('./middleware/auth.js') const db = require('./middleware/db.js')(db) app.use(auth, db)
我相信大多数的读者都更喜欢第二个示例,尤其是在名称可以自解释时。当然,在你写代码时,你能理解它的运行方式。或许,你还会为能将如此多的方法用在一行代码中而沾沾自喜。但是,代码不会说话啊。如果你把代码写的复杂而严谨,当你时隔六个月再来看,或者某天你睡迷糊了或喝醉了来看,理解起它们来会非常困难,更不要说根本不了解其算法和复杂性的同事了。保持简单,这一准则在使用 Node 异步方式的时候特别受用。
有一种 left-pad 事件,不过它只影响了依赖公共注册表的项目,并在 11 分钟之后重新发布。最小化所带来的益处远大于其缺点。而且,npm 已经修改了它的发布策略,任何重要的项目都应该使用缓存或私有注册中心(作为临时解决方案)。
使用异步代码
同步代码确实在 Node 中有一个(低的)位置。 它主要用于编写 CLI 命令或与 Web 应用程序无关的其他脚本。Node 开发者主要构建 Web 应用程序,因此他们使用异步代码,以避免阻塞线程。
例如,这可能是可行的,如果我们只是建立一个数据库脚本,而不是一个系统来处理并行/并发任务:
let data = fs.readFileSync('./acconts.json') db.collection('accounts').insert(data, (results))=>{ fs.writeFileSync('./accountIDs.json', results, ()=>) })
但当建立一个Web应用程序时,这样写会更好:
app.use('/seed/:name', (req, res) => { let data = fs.readFile(`./$.json`, ()=>{ db.collection(req.params.name).insert(data, (results))=>{ fs.writeFile(`./$IDs.json`, results, ()=) }) }) })
区别就在于你是写并发系统(长期运行)还是非并发系统(短期运行)。根据实践经验,我们通常在 Node 中使用异步代码。
避免阻塞请求
Node 有个简单的模板加载系统,它使用的是 CommonJS 模板规范。它内置的 require 函数是将单独存放的模板包含进来的简易方式。不像 AMD/requirejs,Node/CommonJS 的模板加载方式是同步的。require 的工作原理:导入在模板或文件中导出的内容。
const react = require('react')
大多数开发者都不知道 require 有缓存。因此,只要解析的域名没有变化(在 nmp 模板中是没有的), 模块中的代码会只执行一次并将结果保存在一个变量中(同一进程内)。这是一个很不错的优化。然而,即使在缓存的情况下,你也最好把 require 语句放在前面。 看看下面的代码,在真正进入路由的时候才加载 axios 模块。/connect 路由出乎预料的慢,因为它在导入模块的时候才开始请求文件:
app.post('/connect', (req, res) => { const axios = require('axios') axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) })
更好更高效的方式是服务器启动后就加载模块,而不是在路由中:
const axios = require('axios') const express = require('express') app = express() app.post('/connect', (req, res) => { axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) })
了解 require 可被缓存
我在上面提到过 require 可缓存,但有趣的是我们可以在 module.exports 外部进行编码,比如:
console.log('I will not be cached and only run once, the first time') module.exports = () => { console.log('I will be cached and will run every time this module is invoked') }
知道有些代码只运行一次,你可以将这一特点作为优势。
时刻检查错误
Node 不是 Java,在 Java 中,你可以抛出错误,因为大多数时候,当你发现错误时,你会中止应用程序的运行。并且,在 Java 中,你可以通过单独的 try…catch 处理多个错误。
但 Node 不是这样。因为 Node 使用的是事件循环和异步执行,在错误发生时,任何错误都与错误处理程序的上下文分离(比如 try…catch)。下述代码在 Node 中无效:
try { request.get('/accounts', (error, response)=>{ data = JSON.parse(response) }) } catch(error) { // Will NOT be called console.error(error) }
但 try…catch 也可在 Node 同步代码中使用。因此,这是重构前面代码段的更好的方式:
request.get('/accounts', (error, response)=>{ try { data = JSON.parse(response) } catch(error) { // Will be called console.error(error) } })
如果我们不能将 request 调用放在 try…catch 块中,我们就不能处理来自 request 的错误。Node 开发者采用提供包含 error 参数的回调来解决这个问题。这样你需要在每个回调中手工处理错误。你需要检查 error(确保它不是 null),然后将相应的错误消息显示给用户或者客户端,并记录下来。也可以通过调用栈中的 callback 往回传(如果你有回调,而且调用栈上还有另一个函数)。
request.get('/accounts', (error, response)=>{ if (error) return console.error(error) try { data = JSON.parse(response) } catch(error) { console.error(error) } })
你还可以使用 okay 库。 你可以使用以下代码来避免在无数回调中出现手动检查的误差。 (Hello, callback hell).
var ok = require('okay') request.get('/accounts', ok(console.error, (response)=>{ try { data = JSON.parse(response) } catch(error) { console.error(error) } }))
返回回调或使用 if … else
Node 是并发的。因此它有个特点就是,如果不加以注意,就会出现 bug。安全起见,我们使用 return 语句终止执行:
let error = true if (error) return callback(error) console.log('I will never run - good.')
避免由于错误的控制流导致的一些无意的并发(和失败操作)。
let error = true if (error) callback(error) console.log('I will run. Not good!')
确保返回一个回调,以防止继续执行。
监听错误事件
几乎所有的 Node 类/对象都扩展了事件发射器(观察者模式)并发出错误事件。 在错位被破坏之前,这给开发人员提供了捕获错误并处理的机会。
养成使用 .on() 为错误创建事件侦听器的好习惯
var req = http.request(options, (res) => { if (('' + res.statusCode).match(/^2dd$/)) { // Success, process response } else if (('' + res.statusCode).match(/^5dd$/)) // Server error, not the same as req error. Req was ok. } }) req.on('error', (error) => { // Can't even make a request: general error, e.g. ECONNRESET, ECONNREFUSED, HPE_INVALID_VERSION console.log(error) })
了解 npm
很多 Node 开发者和前端开发者都知道—— save(npm install 参数)可以安装一个模板,但要在 package.json 记录模板的版本。当然,还有 save-dev, 用于在 devDependencies 添加记录 (记录生产中不需要的模板)。但你知道用 -S 和 -D 代替 –save 和 –save-dev 吗不妨试试。
在安装模块的时候,去删除 -S 和 -D 为你添加的那些 ^ 记 。它们非常危险,因为它们允许 npm install(或简写为 npm i)从 npm 库中拉取最新的小版本(语义化的版本 中的第2个数)。比如从 v6.1.0 到 v6.2.0 就是一个小版本发布。
结语
更多行业资讯,更新鲜的技术动态,尽在学院。

标签:Node
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!