インターフェイス、プロパティ、メソッド、関数、データ型、およびWeb開発に関連する他のすべてに関する有用なことを書き留めたいです。 だから私は知識のギャップを埋めます。 現在、Node.jsのドキュメントで忙しく、それ以前はHTML、DOM、Web API、CSS、SVG、およびEcmaScriptの資料に取り組んでいました。
Node.jsのドキュメントを読むと、今まで知らなかった多くの素晴らしいことがわかりました。 この短い記事でそれらを共有したいと思います。 最も興味深いものから始めます。 新しい友人に私のガジェットを見せるとき、私は通常同じことをします。
1.ユニバーサルパーサーとしてのクエリ文字列モジュール
次のようなキー/値のペアの配列を生成するいくつかの風変わりなデータベースからデータを取得したとしましょう:
name:Sophie;shape:fox;condition:new
。 これがJavaScriptオブジェクトに簡単に変換できると信じるのは当然です。 したがって、空のオブジェクトを作成し、次に配列を作成して、文字列を「
;
」で分割します
;
「。 次に-この配列の各要素を循環し、「
:
」記号で行を再度分割します。 その結果、各行から取得された最初の要素は新しいオブジェクトのプロパティ名になり、2番目の要素は値になります。
すべてが正しいですか?
いいえ、正しくありません。 同様の状況では、
querystring
を使用するだけで十分です。
const weirdoString = `name:Sophie;shape:fox;condition:new`; const result = querystring.parse(weirdoString, `;`, `:`); // : // { // name: `Sophie`, // shape: `fox`, // condition: `new`, // };
2.デバッグ:V8インスペクター
--inspect
してNodeを実行すると、URLが報告されます。 Chromeでこのアドレスに移動します。 そして今-楽しい驚き。 Chrome開発者ツールを使用してNode.jsをデバッグできます。 幸せな時代が来ました。 Paul Irishのこのトピックに関するガイドを次に示します。
この機能はまだ実験的なものですが、私は喜んで使用していますが、これまでのところ私は失敗していません。
3. nextTickとsetImmediateの違い
他の多くのソフトウェアメカニズムと同様に、これらの2つの関数の違いを覚えるのは、より意味のある名前を付けると非常に簡単です。
したがって、関数
process.nextTick()
は
process.nextTick()
と呼ばれるべきです。
setImmediate()
は
sendThisToTheEndOfTheQueue()
です。
ちなみに、Node v0.10.0以降の
nextTick
最適化に関する有用な資料があります。 少し余談。 Reactの
props
は
stuffThatShouldStayTheSameIfTheUserRefreshes
を呼び出し、
state
stuffThatShouldStayTheSameIfTheUserRefreshes
を呼び出すべきだといつも思ってい
stuffThatShouldBeForgottenIfTheUserRefreshes
。 これらの名前の長さが同じであるという事実は、偶然の一致と考えてください。
4. Server.listenはパラメーターを持つオブジェクトを受け入れます
私は、たとえば、「オプション」という名前のオブジェクトの形式でパラメーターを渡すことを支持しています。関数への入力で多くのパラメーターが予想される場合のアプローチではなく、さらに名前がなく、厳密に定義された順序で配置する必要があります 判明したように、サーバーが要求をリッスンするように構成すると、パラメーターを持つオブジェクトを使用できます。
require(`http`) .createServer() .listen({ port: 8080, host: `localhost`, }) .on(`request`, (req, res) => { res.end(`Hello World!`); });
この便利な機能はかなりよく隠れていました。
http.Server
ドキュメントで、それについての言葉ではありません。 ただし、これは
net.Server
の説明に
net.Server
、その継承者は
http.Server
です。
5.相対ファイルパス
fs
モジュールに渡されるファイルシステムのパスは相対パスです。 参照ポイントは、
process.cwd()
によって返される現在の作業ディレクトリです。 おそらく、誰もがすでにこれを知っていますが、私は常にフルパスなしではできないと思っていました。
const fs = require(`fs`); const path = require(`path`); // ... fs.readFile(path.join(__dirname, `myFile.txt`), (err, data) => { // - }); // ? fs.readFile(`./path/to/myFile.txt`, (err, data) => { // - });
6.ファイルパスの解析
通常、ファイルパスから名前と拡張子を取得する必要があるときは、正規表現を使用しました。 今、私はこれが絶対に必要ないことを理解しています。 同じことは標準の手段でできます。
myFilePath = `/someDir/someFile.json`; path.parse(myFilePath).base === `someFile.json`; // true path.parse(myFilePath).name === `someFile`; // true path.parse(myFilePath).ext === `.json`; // true
7.コンソールでのログの色付け
console.dir(obj, {colors: true})
コンストラクトを使用すると、プロパティと値がコンソールで色付きで強調表示されたオブジェクトを表示できることを知らなかったふりをします。 これにより、ログの読み取りが容易になります。
8.管理setInterval()
たとえば、
setInterval()
を使用して、データベースを1日に1回クリーニングします。 デフォルトでは、
setInterval()
を使用して実行されるようにスケジュールされたコードがあるまで、Nodeイベントループは停止しません。 Nodeに休憩を与えたい場合(これからどのような利点が得られるかわかりません)、
unref()
関数を使用します。
const dailyCleanup = setInterval(() => { cleanup(); }, 1000 * 60 * 60 * 24); dailyCleanup.unref();
ただし、ここでは注意が必要です。 Nodeがビジーでなくなった場合(たとえば、接続を待機しているHTTPサーバーがない場合)、シャットダウンします。
9.プロセスのシグナル完了の定数
殺したいなら、おそらくすでにこれをしているでしょう:
process.kill(process.pid, `SIGTERM`);
このデザインについて悪いことは何も言えません。 しかし、タイプミスによるミスがチームに侵入した場合はどうでしょうか? プログラミングの歴史において、そのようなケースは知られています。 ここの2番目のパラメーターは文字列または対応する整数である必要があるため、何か間違ったことを書いても驚くことではありません。 エラーを防ぐために、これを行うことができます:
process.kill(process.pid, os.constants.signals.SIGTERM);
10. IPアドレスの確認
Node.jsには、 IPアドレスをチェックするための組み込みツールがあります 。 これを行うために、正規表現を複数回記述していました。 より多くの心のために十分ではなかった。 正しい方法は次のとおりです。
require(`net`).isIP(`10.0.0.1`)
4
を返します。
require(`net`).isIP(`cats`)
0
を返し
0
。
そうです、猫はIPアドレスではありません。
例では、文字列に一重引用符を使用していることに気づいたかもしれません。 私はこれを行うのが好きですが、奇妙に見えると思うので、私はこれを言及する必要があると考えますが、私自身は本当に理由を知りません。 一般的に、これは私のスタイルです。
11.行末文字、os.EOL
コードで行末文字を指定したことがありますか? え? すべて、光を消します。 ここでは、特にこれを行った人にとっては素晴らしいことです:
os.EOL
。 Windowsでは、他のすべてのOSで
\r\n
になります-
\n
。
os.EOL
と、異なるオペレーティングシステム間で一貫したコード動作が可能になります。
執筆時点では、このトピックの内容が十分ではないため、ここで修正します。 この投稿の以前のバージョンの読者は、
os.EOL
を使用すると問題が発生する可能性があることを指摘しました。 事実、ここでは特定のファイルでCRLF(
\r\n
)またはLF(
\n
)のいずれかを使用できるという仮定から進む必要がありますが、そのような仮定を完全に確信することはできません。
オープンソースプロジェクトがあり、特定の改行オプションの使用を強制したい場合、 eslintルールがあります。 確かに、Gitがテキストで機能する場合は役に立ちません。
それでも、
os.EOL
は役に立たないおもちゃではありません。 たとえば、このことは、他のオペレーティングシステムに転送する予定のないログファイルを生成する場合に役立ちます。 この場合、
os.EOL
は、たとえばWindows Serverで使用されているメモ帳を表示するために、そのようなファイルの正しい表示を保証します。
const fs = require(`fs`); // CRLF fs.readFile(`./myFile.txt`, `utf8`, (err, data) => { data.split(`\r\n`).forEach(line => { // - }); }); // const os = require(`os`); fs.readFile(`./myFile.txt`, `utf8`, (err, data) => { data.split(os.EOL).forEach(line => { // - }); });
12. HTTPステータスコード
ノードには、HTTPステータスコードとその名前を含む「参照」があります。 私は
http.STATUS_CODES
オブジェクトについて話して
http.STATUS_CODES
ます。 そのキーは状態コードであり、値はその名前です。
オブジェクトhttp.STATUS_CODES
使用方法は次のとおりです。
someResponse.code === 301; // true require(`http`).STATUS_CODES[someResponse.code] === `Moved Permanently`; // true
13.サーバーの不要なシャットダウンの防止
以下のようなコードがサーバーのシャットダウンにつながることは、私にとっていつも少し奇妙に思えました。
const jsonData = getDataFromSomeApi(); // ! ! const data = JSON.parse(jsonData); // .
このようなナンセンスを防ぐために、Node.jsのアプリケーションの先頭に、 未処理の例外をコンソールに表示するような構造を配置できます。
process.on(`uncaughtException`, console.error);
もちろん、私は正しい考えにいるので、私はPM2を使用して、できる限りすべてをラップします
try…catch
注文するようにプログラムするときにブロックを
try…catch
ますが、ホームプロジェクトでは...
このアプローチは決して「 開発のベストプラクティス 」の1つではなく、大規模で複雑なアプリケーションでの使用はおそらく悪い考えであるという事実に特に注意を喚起したいと思います。 誰かが書いたブログ投稿を信頼するか、公式のドキュメントを信頼するかを自分で決めてください。
14.一度だけの短い言葉()
on()
メソッド
on()
加えて、
EventEmitter
オブジェクト
EventEmitter
は
once()
メソッドもあります。 私はこのことを地球上で最後に知っている人であると確信しています。 したがって、私は誰もが理解できる単純な例にとどまります。
server.once(`request`, (req, res) => res.end(`No more from me.`));
15.カスタマイズ可能なコンソール
コンソールは、以下の設計を使用して構成でき、独自の出力ストリームを渡します。
new console.Console(standardOut, errorOut)
なんで? よく分かりません。 たぶん、データをファイル、ソケット、または他の場所に出力するコンソールを作成したいかもしれません。
16. DNSクエリ
NodeがDNSクエリの結果をキャッシュしていないことを口説いた 。 したがって、特定のURLに複数回アクセスすると、不要なクエリに貴重なミリ秒が費やされます。 この場合、
dns.lookup()
を使用して自分でDNSクエリを実行し、結果をキャッシュできます。 または、同じことを行うdnscacheパッケージを使用します。
dns.lookup(`www.myApi.com`, 4, (err, address) => { cacheThisForLater(address); });
17. FSモジュール:地雷原
プログラミングスタイルが私のものに似ている場合、つまり、「ドキュメントを斜めに読み、動作するまでコードをいじります」というようなものであれば、
fs
問題から安全ではありません。 開発者はNodeとさまざまなオペレーティングシステムとの相互作用を統合することを目指して素晴らしい仕事をしましたが、その可能性は無限ではありません。 その結果、さまざまなオペレーティングシステムの機能は、採掘された鋭いサンゴ礁のようなコードの海の表面を破壊します。 このドラマでは、サンゴ礁の1つに乗ることができるボートの役割を果たします。
残念ながら、
fs
関連する違いは、通常の「Windowsと他のすべてのユーザー」に要約されていないため、「Windowsを使用するユーザー」という考えの裏にそれを振り切ることはできません。 (最初は、ここでWeb開発における反Windows感情についてのスピーチ全体を書きましたが、最終的にそれを削除することにしました。さもなければ、私の説教から私の額に目が行きました)。
ここで、一言で言えば、
fs
モジュールのドキュメントで見つけたものです。 これらの啓示は、揚げた鶏よりも悪くない人がいると思います。
-
fs.stats(),
によって返されるオブジェクトのmode
プロパティは、Windowsと他のオペレーティングシステムで異なります。 Windowsでは、fs.constants.S_IRWXU
などのファイルアクセスモード定数に対応しない場合があります。
-
fs.lchmod()
関数はmacOSでのみ使用可能です。
-
type
パラメーターを指定したfs.symlink()
呼び出しは、Windowsでのみサポートされています。
-
fs.watch()
関数に渡すことができるrecursive
オプションは、WindowsおよびmacOSでのみ機能します。
-
fs.watch()
コールバック関数は、LinuxおよびWindowsでのみファイル名を受け入れます。
- ディレクトリの
a+
フラグを指定してfs.open()
を呼び出すと、FreeBSDおよびWindowsで動作しますが、macOSおよびLinuxでは動作しません。
- Linuxで
fs.write()
渡されたposition
パラメーターは、ファイルが接続モードで開かれている場合は無視されます。 カーネルは位置を無視し、ファイルの最後にデータを追加します。
(私はファッションに遅れをとっていない、私はAppleのOSを「macOS」と呼んでいるが、古い名前であるOS Xが別の世界に行ってから2か月経っていない。)
18.ネットモジュールはhttpモジュールの2倍の速度です
Node.jsのドキュメントを読んで、
net
モジュールが重要であることに気付きました。 これは
http
モジュールの下にあります。 これにより、サーバーの相互作用を整理する必要がある場合(判明したため、必要な場合)、
net
モジュールのみを使用する価値があると思いました。
システムのネットワーキングに密接に関与している人は、そのような質問をする必要があるとはまったく信じないかもしれませんが、私は突然サーバーの世界に陥り、HTTPのみを知っているWeb開発者です。 これらすべてのTCP、ソケット、ストリームに関するすべてのこのおしゃべり...私にとっては、 日本のラップのようなものです。 つまり、私には理解できないように思えますが、興味をそそられるように聞こえます。
それを理解し、
net
と
http
で実験し、それらを比較するために、いくつかのサーバーをセットアップし(日本語のラップを聞いていることを願っています)、リクエストをロードしました。 その結果、
http.Server
は1秒あたり約3400のリクエストを処理でき、
http.Server
は約5500でした。さらに、
net.Server
簡単です。
興味があれば、私が実験したクライアントとサーバーのコード。 興味がない場合は、ページを長時間スクロールする必要があることをおizeびします。
これがclient.jsのコードです。
// . – TCP-, – HTTP ( server.js). // . // . const net = require(`net`); const http = require(`http`); function parseIncomingMessage(res) { return new Promise((resolve) => { let data = ``; res.on(`data`, (chunk) => { data += chunk; }); res.on(`end`, () => resolve(data)); }); } const testLimit = 5000; /* ------------------ */ /* -- NET client -- */ /* ------------------ */ function testNetClient() { const netTest = { startTime: process.hrtime(), responseCount: 0, testCount: 0, payloadData: { type: `millipede`, feet: 100, test: 0, }, }; function handleSocketConnect() { netTest.payloadData.test++; netTest.payloadData.feet++; const payload = JSON.stringify(netTest.payloadData); this.end(payload, `utf8`); } function handleSocketData() { netTest.responseCount++; if (netTest.responseCount === testLimit) { const hrDiff = process.hrtime(netTest.startTime); const elapsedTime = hrDiff[0] * 1e3 + hrDiff[1] / 1e6; const requestsPerSecond = (testLimit / (elapsedTime / 1000)).toLocaleString(); console.info(`net.Server handled an average of ${requestsPerSecond} requests per second.`); } } while (netTest.testCount < testLimit) { netTest.testCount++; const socket = net.connect(8888, handleSocketConnect); socket.on(`data`, handleSocketData); } } /* ------------------- */ /* -- HTTP client -- */ /* ------------------- */ function testHttpClient() { const httpTest = { startTime: process.hrtime(), responseCount: 0, testCount: 0, }; const payloadData = { type: `centipede`, feet: 100, test: 0, }; const options = { hostname: `localhost`, port: 8080, method: `POST`, headers: { 'Content-Type': `application/x-www-form-urlencoded`, }, }; function handleResponse(res) { parseIncomingMessage(res).then(() => { httpTest.responseCount++; if (httpTest.responseCount === testLimit) { const hrDiff = process.hrtime(httpTest.startTime); const elapsedTime = hrDiff[0] * 1e3 + hrDiff[1] / 1e6; const requestsPerSecond = (testLimit / (elapsedTime / 1000)).toLocaleString(); console.info(`http.Server handled an average of ${requestsPerSecond} requests per second.`); } }); } while (httpTest.testCount < testLimit) { httpTest.testCount++; payloadData.test = httpTest.testCount; payloadData.feet++; const payload = JSON.stringify(payloadData); options[`Content-Length`] = Buffer.byteLength(payload); const req = http.request(options, handleResponse); req.end(payload); } } /* -- Start tests -- */ // flip these occasionally to ensure there's no bias based on order setTimeout(() => { console.info(`Starting testNetClient()`); testNetClient(); }, 50); setTimeout(() => { console.info(`Starting testHttpClient()`); testHttpClient(); }, 2000);
これがserver.jsです。
// . – TCP, – HTTP. // JSON, , . const net = require(`net`); const http = require(`http`); function renderAnimalString(jsonString) { const data = JSON.parse(jsonString); return `${data.test}: your are a ${data.type} and you have ${data.feet} feet.`; } /* ------------------ */ /* -- NET server -- */ /* ------------------ */ net .createServer((socket) => { socket.on(`data`, (jsonString) => { socket.end(renderAnimalString(jsonString)); }); }) .listen(8888); /* ------------------- */ /* -- HTTP server -- */ /* ------------------- */ function parseIncomingMessage(res) { return new Promise((resolve) => { let data = ``; res.on(`data`, (chunk) => { data += chunk; }); res.on(`end`, () => resolve(data)); }); } http .createServer() .listen(8080) .on(`request`, (req, res) => { parseIncomingMessage(req).then((jsonString) => { res.end(renderAnimalString(jsonString)); }); });
19. REPLモードのトリック
- REPLモードで作業する場合、つまり、ターミナル
node
書き込んでEnterを押すと、.load someFile.js
ようなコマンドを入力でき、システムは要求されたファイルをロードします(たとえば、そのようなファイルに一連の定数を設定できます)。
- このモードでは、環境変数
NODE_REPL_HISTORY=""
を設定して、ファイルへの履歴の書き込みを無効にすることができます。 さらに、過去に移動できるREPL履歴ファイルが~/.node_repl_history
保存されていることがわかりました(少なくとも覚えています)。
- アンダースコア文字「
_»
は、最後に実行された式の結果を格納する変数の名前です。 役に立つと思う。
- NodeがREPLモードで起動すると、モジュールは自動的に(より正確には、要求に応じて)ロードされます。 たとえば、コマンドラインで
os.arch()
と入力するだけで、OSのアーキテクチャを確認できます。require(`os`).arch();
ような構造 必要ありません。
まとめ
ご覧のとおり、ドキュメントを読むことは良いことです。 その地域でさえ、たくさんの新しいものを見つけることができます。 私の発見がお役に立てば幸いです。
ところで、Node.jsについて他に興味深いことはありますか? もしそうなら-共有:)