ホームページ  >  記事  >  ウェブフロントエンド  >  2017 年に優れたノード開発者になるための 10 のヒント

2017 年に優れたノード開発者になるための 10 のヒント

阿神
阿神オリジナル
2017-01-24 11:40:351150ブラウズ

以下に、2017 年により優れた Node 開発者になるのに役立つ 10 の提案をリストします。このアドバイスの一部は私が日々の実践で学んだものであり、また一部は最も人気のある Node モジュールと npm モジュールを作成した人々から学んだものです。 これから説明する内容は次のとおりです:

1.複雑さを避ける — コードのチャンクを可能な限り小さいサイズに分割します。

2.非同期プログラミングを使用する — 疫病のような同期コードを避けてください。

3. require ブロックを避ける — require は同期であり、コードの実行をブロックするため、すべての require ステートメントをファイルの先頭に置きます。

4.必要なキャッシュを理解する — 知っていればそれを活用できますが、そうでないとバグが発生する可能性があります。

5.常にエラーをチェックする — エラーはフットボールではありません。決してエラーをスローしたり、エラーチェックをスキップしたりしないでください。

6.try...catch は同期コード内でのみ使用してください — try...catch は非同期コードでは効果がありません。 V8 エンジンは try...catch 用に最適化できません。

7.コールバックを返すか、if ... else を使用します — 実行が続行されないことを保証するためだけにコールバックを返します。

8.エラー イベントをリッスンする — ほぼすべての Node クラス/オブジェクトにはイベント エミッター (オブザーバー モード) があり、エラー イベントをブロードキャストします。必ずリッスンしてください。

9.npm を理解する — モジュールをインストールするには、--save または --save-dev` の代わりに -S または -D を使用します。

10.package.json で正確なバージョン番号を使用します: -S を使用してモジュールをインストールする場合、npm は自動的にデフォルトのバージョン番号を使用します。バージョン番号をロックするには手動で変更する必要があります。オープン ソース モジュールでない限り、プロジェクト内の SemVer (Semantic Versioning Standard) を信頼しないでください。

11. ボーナスポイント — さまざまな依存関係を使用します。開発段階でプロジェクトに必要なものを devDependency に配置します。npm i --production を使用することを忘れないでください。冗長な依存関係が多いほど、問題が発生するリスクが高くなります。

それでは、上記の点を一つずつ理解していきましょう。


複雑さを避ける

npmの作成者であるIsaac Z. Schlueterによって書かれたいくつかのモジュールを見てみましょう。たとえば、use-strict、このモジュールは使用を強制するために使用されますJavascript の場合 厳密モードでは、このモジュールには 3 行のコードしかありません:

var module = require('module')
module.wrapper[0] += '"use strict";'
Object.freeze(module.wrap)

では、なぜ複雑さを避ける必要があるのでしょうか? アメリカ海軍から生まれた有名なフレーズです: KEEP IT SIMPLE STUPID (または「シンプルであれ、愚か者」)。それが理由です。人間の脳は、一度に作業記憶に 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)

2 番目の例は、特に名前を見ただけで機能が理解できるため、ほとんどの人が気に入ると思います。昔、コードを書いていたとき、おそらくそれがどのように機能するかを理解していると思っていたでしょう。あるいは、複数の関数を同じ線上に接続することで、自分がどれだけ賢いのかを示したい場合でも。しかし、あなたは愚かなコードを書いています。このコードを複雑に考えて書いてしまうと、将来このコードを見たときに理解するのが難しくなります。特に Node の非同期コードでは、コードを単純にしてください。

もちろん、左パッド イベントが発生しますが、実際には左パッド モジュールに依存するプロジェクトにのみ影響し、11 分後に代替モジュールがリリースされました。コードの最小化による利点は、その欠点を上回ります。 npm はリリース ポリシーを変更し、本格的なプロジェクトはキャッシュされたリポジトリまたはプライベート リポジトリを (一時的な解決策として) 使用する必要があります。


非同期プログラミングの使用

Node でのコードの同期にはほんの一部しかかかりません。このコードの大部分は、Web アプリケーションとは関係のないコマンド ライン ツールまたはその他のスクリプト用です。ほとんどの Node 開発者は 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 では常に非同期コードを使用してください。


ブロック要求を回避する

Node には、CommonJS モジュール形式を使用したシンプルなモジュール読み込みシステムがあります。これは、異なるファイルにモジュールを簡単に導入できる require 関数に基づいています。 AMD/requirejs とは異なり、Node/CommonJS モジュールは同期的にロードされます。 require の仕組みは次のとおりです: モジュールのコンテンツまたはファイルのエクスポートを導入します:

`const react = require('react')`

但是大多数的开发者并不知道require是会被缓存的。因此,只要解析的文件名(resolved filename)没有剧烈的变化(比如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会被缓存

我在上面一节已经提到了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在同步代码中是可以被用的。前面的代码片段可以被更好的重构为:

request.get('/accounts', (error, response)=>{
  try {
    data = JSON.parse(response)
  } catch(error) {
    // Will be called
    console.error(error)
  }
})

如果我们无法将request的返回内容包裹在try...catch中,那么我们将没有办法去处理请求的错误。Node的开发者通过在返回的参数里面加上error来解决了这个问题。因此,我们需要在每一个回调中手动去处理错误。你可以去检查这些错误(判断error不是null),然后展示错误信息给用户或者展示在客户端上并且记录它, 或者你可以通过调用 callback ,给它传 error 参数,将错误传回给上一级调用栈(如果你在调用栈之上有另一个回调函数)。

request.get('/accounts', (error, response)=>{
  if (error) return console.error(error)
  try {
    data = JSON.parse(response)
  } catch(error) {
    console.error(error)
  }
})

一个小技巧是你可以使用okay库。你可以像下面的例子一样使用它去避免在回调地狱中手动去检查错误(你好, 回调地狱).

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!')

请确保使用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会在安装模块的同时,会在package.json保存一条含有模块版本信息的条目。当然,还有--save-dev可以用于安装devDependencies(在生成环境中不需要的模块)。但是你知道用-S和-D是否可以代替--save 和--save-dev么?答案是可以的。

当你安装模块的时候,你需要删除-S和-D自动为你模块的版本号添加的^标签。否者当你使用npm install(或者npm i)安装模块的时候,就会自动拉取最新的镜像(版本号的第二位数字)。例如v6.1.0就是v6.2.0的一个镜像分支。

npm团队推荐使用semver,但是你最好不要这样。npm团队认为开源开发者会遵守semver所以他们在npm安装时自动加上了^。没有人可以去保证,所以最好是锁定你的版本号。更好的办法是使用shrinkwrap:npm shrinkwrap会生成一个包含依赖的具体版本的文件。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。