链表首节点成为尾节点
来宾作者Azat Mardan撰写了2017年成为更好的节点开发人员的10条技巧。 SitePoint访客帖子旨在为您带来来自Web社区知名作家和演讲者的引人入胜的内容。
注意:本文的原始标题为The Platform的Gurus提供的The Best Node Practices。 本文介绍的是真实,经过尝试和测试的模式,而不是2017年的最佳模式。尽管如此,Node gurus的一些良好旧做法仍将在2017年和2018年甚至在2019年应用,新的前沿功能(例如async /等待中,诺言不在此处。 这是因为这些新功能不在Node core或npm,Express等流行项目的代码中。本文的第二部分将反映内容的适当性质。
本文包含在我们的选集Modern JavaScript中 。 如果您希望所有内容都集中在一个地方,以适应最新JavaScript,请注册SitePoint Premium并下载一个副本。
当我加入Storify时,我于2012年开始全职使用Node。 从那时起,我再也没有回过头,也没有感到自己错过了Python,Ruby,Java或PHP(这是我在过去十年的Web开发中曾使用的语言)。
Storify对我来说是一项有趣的工作,因为与许多其他公司不同,Storify在JavaScript上运行(甚至可能仍在运行)所有内容。 您会看到,大多数公司,尤其是大型公司,例如PayPal,Walmart或Capital One,仅将Node用于其堆栈的某些部分。 通常,他们将其用作API网关或业务流程层。 那很棒。 但是对于软件工程师来说,没有什么比完全沉浸到Node环境更胜一筹了。
在这篇文章中,我将概述十个技巧,以帮助您在2017年成为更好的Node开发人员。这些技巧来自我(他们在saw沟中看到并学习了它们)以及编写了最受欢迎的Node和npm模块的人。 这是我们要介绍的内容:
- 避免复杂性 -将代码组织成尽可能小的块,直到看起来太小然后使其变得更小为止。
- 使用异步代码 -避免使用类似瘟疫的同步代码。
- 避免阻止require —将所有require语句放在文件顶部,因为它们是同步的并且会阻止执行。
- 知道需求已被缓存 -这可能是功能或代码中的错误。
- 始终检查错误 -错误不是足球。 永远不要抛出错误,也不要跳过错误检查。
- 仅在同步代码中使用try ... catch -
try...catch
对于异步代码没有用,而且V8无法在try...catch
和普通代码中优化代码。 - 返回回调或使用if…else –可以肯定的是,返回回调以防止执行继续。
- 侦听错误事件 —几乎所有Node类/对象都扩展了事件发射器(观察者模式)并发出
error
事件。 一定要听。 - 了解您的npm —使用
-S
或-D
而不是--save
或--save-dev
安装模块 - 在package.json中使用确切的版本 :默认情况下,当您使用
-S
,npm愚蠢地添加一个插入符号,因此请手动删除它们以锁定版本。 切勿在您的应用程序中信任semver,而在开源模块中信任它。 - 奖励 -使用不同的依赖项。 将项目所需的内容仅放在
devDependencies
中进行开发,然后使用npm i --production
。 您拥有的不需要的依赖项越多,遭受漏洞攻击的风险就越大。
因此,让我们一分为二,分别看看其中的每个。 我们可以?
而且请不要忘记:如上所述,这是第一部分。 您可以在第二部分中找到另外十个技巧 。
避免复杂性
看一下npm的创建者Isaac Z. Schlueter编写的一些模块。 例如, 使用严格的强制实施JavaScript模块严格模式,它只是三行代码:
var module = require('module')
module.wrapper[0] += '"use strict";'
Object.freeze(module.wrap)
那么为什么要避免复杂性呢? 根据一个传说,起源于美国海军的一个著名短语宣称:保持简单愚蠢 (或者“保持简单,愚蠢” ?)。 那是有原因的。 人脑在任何时候只能在其工作记忆中保留五到七个项目。 这只是事实。
通过将您的代码模块化成较小的部分,您和其他开发人员可以更好地理解和推理它。 您也可以对其进行更好的测试。 考虑这个例子,
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来说,保持简单尤为重要。
是的,发生了左倾事件,但仅影响了依赖于公共注册表的项目,替代项目在11分钟内发布。 缩小规模的好处远大于缺点。 另外,npm 更改了其未发布策略 ,任何严肃的项目都应使用缓存策略或私有注册表(作为临时解决方案)。
使用异步代码
同步代码在Node中确实有一个(很小的)位置。 它主要用于编写CLI命令或与Web应用程序无关的其他脚本。 节点开发人员主要构建Web应用程序,因此他们使用异步代码来避免阻塞线程。
例如,如果我们只是构建数据库脚本,而不是处理并行/并发任务的系统,则可能没问题:
let data = fs.readFileSync('./acconts.json')
db.collection('accounts').insert(data, (results))=>{
fs.writeFileSync('./accountIDs.json', results, ()=>{process.exit(1)})
})
但这在构建Web应用程序时会更好:
app.use('/seed/:name', (req, res) => {
let data = fs.readFile(`./${req.params.name}.json`, ()=>{
db.collection(req.params.name).insert(data, (results))=>{
fs.writeFile(`./${req.params.name}IDs.json`, results, ()={res.status(201).send()})
})
})
})
区别在于您是在编写并发(通常是长时间运行)还是非并发(短时间运行)系统。 根据经验,请始终在Node中编写异步代码。
避免阻塞要求
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
Node具有一个简单的模块加载系统,该系统使用CommonJS模块格式。 其内置的require
函数是包含存在于单独文件中的模块的简便方法。 与AMD / requirejs不同,Node / CommonJS模块加载方式是同步的。 require
工作的方式是: 导入模块或文件中导出的内容 。
const react = require('react')
大多数开发人员不知道require
是被缓存的。 因此,只要不对解析的文件名进行任何大的更改(对于npm模块,则没有任何更改),那么模块中的代码将被执行一次并加载到变量中(对于该过程)。 这是一个不错的优化。 但是,即使使用缓存,最好还是先放置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
缓存,但是有趣的是我们可以在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')
}
知道某些代码只能运行一次,因此可以利用此功能。
始终检查错误
节点不是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
仍然可以在同步节点代码中使用。 因此,这是对先前代码段的更好重构:
request.get('/accounts', (error, response)=>{
try {
data = JSON.parse(response)
} catch(error) {
// Will be called
console.error(error)
}
})
如果我们无法将request
调用包装在try...catch
块中,则会使我们有来自未处理请求的错误。 节点开发人员通过为您提供error
作为回调参数来解决此问题。 因此,您需要始终手动处理每个回调中的error
。 为此,您可以检查错误(确保它不是null
),然后将错误消息显示给用户或客户端并记录下来,或者通过调用带error
的回调将其传递回调用堆栈(如果有)回调和调用堆栈中的另一个函数)。
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)
}
}))
返回回调或在…否则使用
节点是并发的。 因此,如果您不小心,此功能可能会变成错误。 为了安全起见,请使用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!')
可以肯定的是, return
一个回调以防止执行继续。
听error
事件
几乎所有Node类/对象都扩展了事件发射器(观察者模式)并发出error
事件。 这为开发人员提供了一个机会,可以抓住这些烦人的错误并在造成严重破坏之前进行处理。
养成使用.on()
创建error
事件监听器的好习惯:
var req = http.request(options, (res) => {
if (('' + res.statusCode).match(/^2\d\d$/)) {
// Success, process response
} else if (('' + res.statusCode).match(/^5\d\d$/))
// 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 i
中提取最新的次要版本(语义版本中的第二个数字)。 例如,v6.1.0到v6.2.0是次要发行版。
npm团队相信semver ,但您不应该这样做。 我的意思是,他们之所以选择插入符号^
是因为他们相信开源开发人员不会在次要版本中引入重大更改。 没有人理智地相信它。 锁定您的版本。 更好的是,使用收缩包装 : npm shrinkwrap
将创建一个新文件,其中包含依赖的确切版本。
结论
这篇文章是两个的一部分。 从使用回调和异步代码到检查错误和锁定依赖关系,我们已经涵盖了很多基础。 希望您在这里找到了新的东西或有用的东西。 如果喜欢,请务必阅读第二部分: 10个Node.js最佳实践:Node Gurus的启发 。
告诉我你的想法。 我错过了什么吗? 你做的不一样吗? 在下面的评论中让我知道。
翻译自: https://www.sitepoint.com/10-tips-to-become-a-better-node-developer/
链表首节点成为尾节点