Node.js とは何ですか? [closed] 質問する

Node.js とは何ですか? [closed] 質問する

よく分からないNode.jsについてです。私が主に Web ベースのビジネス アプリケーション開発者だからかもしれません。それとは何ですか? また、それの用途は何ですか?

これまでのところ、私の理解は次のとおりです。

  1. プログラミングモデルはイベント駆動型であり、特に処理方法は入出力
  2. それは使用していますJavaScriptそしてパーサーはV8
  3. 同時実行サーバー アプリケーションを簡単に作成できます。

私の理解は正しいでしょうか? 正しい場合、イベント I/O の利点は何ですか? 同時実行性に関する利点が多いのでしょうか? また、Node.js は JavaScript ベース (V8 ベース) のプログラミング モデルのようなフレームワークになる方向に向かっているのでしょうか?

ベストアンサー1

私は仕事で Node.js を使っていますが、とてもパワフルだと感じています。Node.js を一言で表現するなら、「興味深い」でしょう (これは純粋に肯定的な形容詞ではありません)。コミュニティは活気に満ち、成長しています。JavaScript は、その奇妙さにもかかわらず、コーディングに最適な言語です。そして、あなたは毎日、「ベスト プラクティス」と構造化されたコードのパターンについての自分の理解を再考するでしょう。現在、Node.js には膨大なアイデアのエネルギーが流れ込んでおり、Node.js で作業すると、こうした思考すべてに触れることになります。これは、精神的な大きな負担です。

Node.js を本番環境で使うことは確かに可能ですが、ドキュメントで約束されているような「ターンキー」展開にはほど遠いものです。Node.js v0.6.x では、「cluster」がプラットフォームに統合され、重要な構成要素の 1 つを提供していますが、私の「production.js」スクリプトは、ログ ディレクトリの作成、デッド ワーカーのリサイクルなどを処理するために、依然として約 150 行のロジックで構成されています。「本格的な」本番サービスでは、着信接続を制限し、Apache が行うすべてのことを行う準備も必要です。PHP の。 公平であるために、ルビーオンレールこの問題がまさに存在します。これは2つの補完なメカニズムによって解決されます: 1) Ruby on Rails/Node.jsを専用のWebサーバー(C言語で書かれ、徹底的にテストされた)の背後に置くエンギンクス(またはアパッチ/ライトウェブサーバーは、静的コンテンツ、アクセスログ、URLの書き換え、終了を効率的に提供できます。証明書アクセスルールを適用し、複数のサブサービスを管理します。実際のノードサービスにヒットするリクエストについては、Webサーバーがリクエストをプロキシします。2) 次のようなフレームワークを使用します。ユニコーンワーカー プロセスを管理し、定期的にリサイクルするなどします。完全に完成した Node.js サービング フレームワークはまだ見つかっていません。存在するかもしれませんが、私はまだ見つけておらず、手作りの「production.js」で約 150 行を使用しています。

次のようなフレームワークを読む急行標準的なやり方は、すべてを 1 つの万能 Node.js サービスで提供することであるように思われます...「app.use(express.static(__dirname + '/public'))」。負荷の低いサービスや開発では、おそらくそれで問題ありません。しかし、サービスに大きな負荷をかけ、24 時間 365 日稼働させようとすると、大規模なサイトが次のようなよく練られた堅牢な C コードを必要とする理由がすぐにわかります。エンギンクスサイトのフロントを務め、静的コンテンツリクエストをすべて処理します(...電子商取引ネットワーク、 のようにAmazon クラウドフロント))。これに関する、いくぶんユーモラスで、あからさまに否定的な見解については、この男

Node.jsはサービス以外の用途でもますます利用されるようになっています。Webコンテンツを提供するために他のものを使用している場合でも、Node.jsをビルドツールとして使用することができます。ネプコードを整理するためのモジュール、ブラウザ化それを一つの資産にまとめ、uglify js の最新バージョンをダウンロードウェブを扱うにはJavaScriptが最適だインピーダンス整合そして、多くの場合、それが最も簡単な攻撃ルートになります。たとえば、翻訳レスポンスペイロードには、私のアンダースコア CLIモジュール、構造化データのユーティリティ ベルト。

長所短所:

  • 利点: サーバー担当者にとって、バックエンドで JavaScript を記述することは、最新の UI パターンを学習するための「入門薬」となっています。クライアント コードを書くのが怖くなくなりました。
  • 利点: 適切なエラー チェックが促進される傾向があります (事実上すべてのコールバックによって err が返され、プログラマーに処理を要求します。また、async.js やその他のライブラリは、「これらのサブタスクのいずれかが失敗した場合は失敗する」というパラダイムを、一般的な同期コードよりもはるかに適切に処理します)
  • 利点: 実行中のタスクのステータスの取得、ワーカー間の通信、キャッシュ状態の共有など、興味深く通常は難しいタスクが簡単になります。
  • 長所: 強力なパッケージ マネージャー (npm) に基づく巨大なコミュニティと多数の優れたライブラリ
  • 短所: JavaScript には標準ライブラリがありません。機能をインポートすることに慣れすぎていて、JSON.parse や npm モジュールの追加を必要としない他の組み込みメソッドを使用すると違和感を覚えます。つまり、すべてのものに 5 つのバージョンがあるということです。Node.js の「コア」に含まれるモジュールにも、デフォルトの実装に満足できない場合に備えて、さらに 5 つのバリエーションがあります。これにより、急速な進化がもたらされますが、ある程度の混乱も生じます。

単純な1リクエスト1プロセスモデル(ランプ):

  • 利点: 数千のアクティブ接続に拡張可能。非常に高速で効率的。Web フリートの場合、PHP や Ruby と比較して必要なボックスの数が 10 分の 1 に削減される可能性があります。
  • 利点: 並列パターンの記述は簡単です。3つ(またはN)のBLOBをフェッチする必要があると想像してください。メムキャッシュこれをPHPで実行すると...最初のBLOBを取得し、次に2番目、3番目を取得するコードを書いたのですか? うわー、遅いですね。特別なペックMemcached の特定の問題を修正するモジュールがありますが、データベース クエリと並行して Memcached データを取得したい場合はどうすればよいでしょうか。Node.js ではパラダイムが非同期であるため、Web リクエストで複数の処理を並行して実行することは非常に自然なことです。
  • 短所: 非同期コードは同期コードよりも根本的に複雑であり、同時実行が実際に何を意味するのかをしっかりと理解していない開発者にとっては、事前の学習曲線が困難になる可能性があります。それでも、ロック付きのあらゆる種類のマルチスレッド コードを記述するよりもはるかに簡単です。
  • 欠点: 計算負荷の高いリクエストが、例えば100ミリ秒間実行されると、同じNode.jsプロセスで処理されている他のリクエストの処理が停止します。協調マルチタスクこれは、Web Workers パターン (サブプロセスを分離して、コストのかかるタスクを処理する) で軽減できます。または、多数の Node.js ワーカーを使用して、各ワーカーが同時に 1 つのリクエストのみを処理できるようにすることもできます (プロセスのリサイクルがないため、それでもかなり効率的です)。
  • 短所:本番システムの運用は、CGApache + PHPのようなモデル、パールルビーなど。処理されない例外はプロセス全体を停止させ、失敗したワーカーを再起動するロジックが必要になります(集まる)。バグのあるネイティブ コードを持つモジュールは、プロセスをハードクラッシュさせる可能性があります。ワーカーが終了すると、そのワーカーが処理していたリクエストはすべて破棄されるため、バグのある API が 1 つあるだけで、共ホストされている他の A​​PI のサービスが簡単に低下する可能性があります。

Java / C# / C (C? 本当に?) で「本物の」サービスを書くのと比べると

  • 利点: Node.js で非同期処理を実行するのは、他の場所でスレッド セーフを実行するよりも簡単で、おそらくより大きなメリットがあります。Node.js は、私がこれまで使用した非同期パラダイムの中で、最も苦痛の少ないパラダイムです。優れたライブラリを使用すれば、同期コードの作成よりも少しだけ難しくなります。
  • 利点: マルチスレッド/ロックのバグがない。確かに、ブロッキング操作のない適切な非同期ワークフローを表現するより冗長なコードを書くために前もって投資する必要があります。そして、いくつかのテストを書いて、それが機能するようにする必要があります (スクリプト言語であり、変数名のファットフィンガーリングは単体テスト時にのみ検出されます)。しかし、一度それが機能するようになれば、ハイゼンバグ-- 100 万回の実行で 1 回しか現れない奇妙な問題 -- その表面積ははるかに小さくなります。Node.js コードを書く負担は、コーディング フェーズに大きく先行します。その結果、安定したコードになる傾向があります。
  • 利点: JavaScriptは機能を表現するのに非常に軽量です。言葉で証明するのは難しいですが、翻訳動的型付け、ラムダ表記、プロトタイプ継承、軽量モジュールなど、何でも...同じアイデアを表現するのに必要なコードが少なくなる傾向があります。
  • 短所: おそらく、Java でのコーディング サービスが本当に好きなのではないでしょうか。

JavaScriptとNode.jsに関する別の視点については、Java から Node.js へJava 開発者が Node.js を学習した感想と経験について書いたブログ記事です。


モジュールNode.jsを検討する際は、JavaScriptライブラリの選択があなたの体験を決定づけるということを覚えておいてください。ほとんどの人は、非同期パターンヘルパー(Step、Futures、Async)とJavaScriptシュガーモジュール(アンダースコア)。

ヘルパー / JavaScript シュガー:

  • アンダースコア- これを使ってください。そうしてください。_.isString() や _.isArray() などのコードが読みやすくなります。それ以外に安全なコードを書く方法がわかりません。また、強化されたコマンドライン機能については、私の独自のものをご覧ください。アンダースコア CLI

非同期パターンモジュール:

  • ステップ- シリアルアクションとパラレルアクションの組み合わせを表現する非常にエレガントな方法です。個人的にお勧めします。私の投稿ステップコードがどのようになるかについて。
  • 先物- 要件を通じて順序を表現するための、はるかに柔軟な (これは本当に良いことでしょうか?) 方法です。「a、b、c を並行して開始します。A と B が終了したら、AB を開始します。A と C が終了したら、AC を開始します。」などの表現が可能です。このような柔軟性には、ワークフローのバグを回避するためのより注意が必要です (コールバックを呼び出さない、または複数回呼び出すなど)。Raynosの投稿futures の使用について (これは私が futures を「理解」するきっかけとなった投稿です)。
  • 非同期- 各パターンに 1 つのメソッドがある、より伝統的なライブラリ。私は、Step に熱心に転向し、その後、Async のすべてのパターンを、より読みやすい単一のパラダイムで Step で表現できることに気付く前に、このライブラリを使い始めました。
  • タメJS- OKCupid によって書かれたプリコンパイラーで、シリアルおよび並列ワークフローをエレガントに記述するための新しい言語プリミティブ「await」が追加されています。パターンは素晴らしいようですが、プリコンパイルが必要です。私はまだこれについて決めかねています。
  • ストリームラインJS- TameJS の競合製品。私は Tame に傾いていますが、ご自分で判断してください。

非同期ライブラリの詳細については、以下を参照してください。このパネルインタビュー著者らと共に。

ウェブフレームワーク:

  • 急行ウェブサイトを整理するための優れたRuby on Rails風のフレームワーク。ジェイドXML/HTML テンプレート エンジンとして使用することで、HTML の構築がはるかに簡単になり、ほとんどエレガントになります。
  • jQueryjQueryは技術的にはノードモジュールではありませんが、クライアント側のユーザーインターフェースの事実上の標準になりつつあります。jQueryはCSSのようなセレクターを提供し、DOM要素のセットを「クエリ」して、その後操作(ハンドラー、プロパティ、スタイルなど)することができます。同様に、TwitterのブートストラップCSSフレームワーク、バックボーンのためにMVCC のパターン、そしてブラウザすべての JavaScript ファイルを 1 つのファイルにまとめます。これらのモジュールはすべて事実上の標準になりつつあるので、聞いたことがない場合は少なくとも調べてみてください。

テスト:

  • JSHint- 使用する必要があります。最初はこれを使わなかったのですが、今では理解できないようです。JSLint は、Java のようなコンパイル言語で得られる基本的な検証を多数追加します。括弧の不一致、宣言されていない変数、さまざまな形やサイズの typeos などです。また、私が「アナル モード」と呼んでいる、空白のスタイルなどを検証するさまざまな形式をオンにすることもできます。それがお好みなら問題ありませんが、本当の価値は、コードを実行して問題のある行に行かなくても、閉じる ")" を忘れた正確な行番号を即座にフィードバックできることです。"JSHint" は、より構成可能なバリアントです。ダグラス・クロックフォードJSLint
  • モカ私が好み始めている Vows の競合製品です。どちらのフレームワークも基本的な部分は十分に処理しますが、複雑なパターンは Mocha で表現する方が簡単な傾向があります。
  • 誓いVows は実にエレガントです。また、どのテストケースが成功/失敗したかを示す素敵なレポート (--spec) を出力します。30 分かけて学習すれば、最小限の労力でモジュールの基本的なテストを作成できます。
  • ゾンビ- HTMLとJavaScriptのヘッドレステストJSDom仮想「ブラウザ」として。非常に強力な機能です。リプレイブラウザ内コードの決定論的テストを超高速で実行します。
  • テストについて「考える」方法に関するコメント:
    • テストは必須です。JavaScript のような動的言語では、静的チェックはほとんどありません。たとえば、4 つのパラメータを期待するメソッドに 2 つのパラメータを渡しても、コードが実行されるまでエラーは発生しません。JavaScript でバグが発生するハードルはかなり低いです。コンパイル言語での検証ギャップを埋めるには、基本的なテストが不可欠です。
    • 検証は忘れて、コードを実行するだけにしてください。すべてのメソッドについて、私の最初の検証ケースは「何も壊れない」であり、これが最も頻繁に発生するケースです。コードがスローされることなく実行されることを証明すると、80% のバグがキャッチされ、コードの信頼性が大幅に向上するため、戻ってスキップした微妙な検証ケースを追加することになります。
    • 小さく始めて、慣性の壁を破りましょう。私たちは皆怠け者で、時間に追われており、テストを「余分な作業」と見なすのは簡単です。ですから、小さく始めましょう。テスト ケース 0 を書いて、モジュールをロードして成功を報告します。これだけのことを自分に強制すれば、テストに対する慣性の壁は破られます。初めて行う場合は、ドキュメントを読むことも含めて 30 分未満です。次に、テスト ケース 1 を書いて、メソッドの 1 つを呼び出して「何も壊れていない」、つまりエラーが返されないことを確認します。テスト ケース 1 は 1 分もかからないはずです。慣性がなくなると、テスト範囲を段階的に拡張するのが簡単になります。
    • 次に、コードに合わせてテストを進化させます。モック サーバーなどを使用した「正しい」エンドツーエンド テストがどのようなものになるかに怯えないでください。コードは最初はシンプルですが、新しいケースに対応できるように進化します。テストも同様です。コードに新しいケースや新しい複雑さを追加したら、新しいコードを実行するためのテスト ケースを追加します。バグが見つかったら、検証や新しいケースを追加して、欠陥のあるコードをカバーします。デバッグ中にコードの一部に自信がなくなった場合は、戻ってテストを追加し、想定どおりに動作していることを証明します。サンプル データの文字列 (呼び出す他のサービス、スクレイピングする Web サイトなど) をキャプチャし、解析コードに入力します。ここでいくつかのケース、そこで検証を改善すれば、信頼性の高いコードが完成します。

また、公式リスト推奨されるNode.jsモジュール。ただし、GitHubの ノードモジュール Wikiはるかに完全で優れたリソースです。


Node を理解するには、いくつかの重要な設計上の選択を考慮すると役立ちます。

Node.js はイベントベースで、非同期/非ブロッキングです。HTTP 接続の受信などのイベントが発生すると、JavaScript 関数が起動します。この関数は少しの作業を行い、データベースへの接続や別のサーバーからのコンテンツの取得などの他の非同期タスクを開始します。これらのタスクが開始されると、イベント関数は終了し、Node.js はスリープ状態に戻ります。データベース接続が確立されたり、外部サーバーがコンテンツで応答したりするなど、他のことが発生するとすぐに、コールバック関数が起動し、さらに多くの JavaScript コードが実行され、さらに多くの非同期タスク (データベース クエリなど) が開始される可能性があります。このように、Node.js は複数の並列ワークフローのアクティビティを適切にインターリーブし、いつでもブロックされていないアクティビティを実行します。これが、Node.js が何千もの同時接続をうまく管理できる理由です。

他のみんなのように、接続ごとに 1 つのプロセス/スレッドを使用すればいいのではないでしょうか。Node.jsでは、新しい接続はごく小さなヒープ割り当てにすぎません。新しいプロセスを起動するには、かなり多くのメモリが必要で、プラットフォームによっては 1 メガバイト必要になります。しかし、実際のコストはコンテキスト切り替えに関連するオーバーヘッドです。カーネル スレッドが 10^6 個ある場合、カーネルは次にどのプロセスを実行するかを判断するために多くの作業を行う必要があります。Linux 用の O(1) スケジューラの構築には多くの作業が費やされましたが、結局のところ、CPU 時間を奪い合う 10^6 個のプロセスよりも、単一のイベント駆動型プロセスの方がはるかに効率的です。また、過負荷状態では、マルチプロセス モデルの動作が非常に悪くなり、特に SSHD などの重要な管理サービスが飢餓状態になります (つまり、ボックスにログインして、実際にどれほど問題になっているかを把握することさえできません)。

Node.js はシングル スレッドロック フリーです。Node.js は、非常に慎重な設計選択として、プロセスごとに 1 つのスレッドしかありません。このため、複数のスレッドが同時にデータにアクセスすることは基本的に不可能です。したがって、ロックは必要ありません。スレッドは難しいです。本当に本当に難しいです。それを信じないのであれば、スレッド プログラミングを十分に行っていないということです。ロックを正しく行うことは難しく、追跡が非常に難しいバグが発生します。ロックとマルチスレッドを排除すると、最も厄介なバグの 1 つがなくなります。これが、Node の最大の利点かもしれません。

しかし、16 コア ボックスをどのように活用すればよいのでしょうか?

ふたつのやり方:

  1. イメージエンコードのような大規模で負荷の高い計算タスクの場合、Node.js は子プロセスを起動したり、追加のワーカープロセスにメッセージを送信したりできます。この設計では、1 つのスレッドでイベントのフローを管理し、N 個のプロセスで負荷の高い計算タスクを実行して、他の 15 個の CPU を消費します。
  2. ウェブサービスのスループットをスケーリングするには、1つのボックスでコアごとに1つのNode.jsサーバーを複数実行する必要があります。集まる(Node.js v0.6.x では、ここにリンクされている公式の「cluster」モジュールが、異なる API を持つ learnboost バージョンに取って代わります)。これらのローカル Node.js サーバーは、ソケット上で競合して新しい接続を受け入れ、負荷を分散します。接続が受け入れられると、これらの共有プロセスの 1 つにしっかりとバインドされます。理論上は、これは良くないように思えますが、実際には非常にうまく機能し、スレッドセーフなコードを書くという面倒な作業を避けることができます。また、これは、Node.js が優れた CPU キャッシュ アフィニティを取得し、メモリ帯域幅をより効率的に使用することを意味します。

Node.jsを使えば、簡単に強力な機能を実現できます。さまざまなタスクを実行し、TCPコマンド用のポート、いくつかの画像のエンコードなど。5 行のコードで、アクティブなタスクの現在のステータスを表示する HTTP ベースの Web 管理ポータルを追加できます。これは簡単に実行できます。

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(myJavascriptObject.getSomeStatusInfo());
}).listen(1337, "127.0.0.1");

これで、URL を入力して実行中のプロセスのステータスを確認できます。ボタンをいくつか追加すると、「管理ポータル」が完成します。実行中の Perl / Python / Ruby スクリプトがある場合、「管理ポータルを追加する」だけでは簡単ではありません。

しかし、JavaScript は遅い / 悪い / 邪悪な / 悪魔の産物ではないでしょうか。JavaScript には奇妙な点がいくつかありますが、「良い部分」を合わせると非常に強力な言語となり、いずれにせよ、JavaScript はクライアント (ブラウザー) の言語です。JavaScript は今後も存在し続けます。他の言語は IL として JavaScript をターゲットにしており、世界クラスの才能が最先端の JavaScript エンジンを生み出すために競い合っています。ブラウザーにおける JavaScript の役割のため、JavaScript を超高速にするために膨大なエンジニアリング努力が注がれています。V8少なくとも今月は、最新かつ最高のJavaScriptエンジンです。効率と安定性の両方で他のスクリプト言語を圧倒しています(Rubyを見てください)。そして、Microsoft、Google、Mozillaの大規模なチームがこの問題に取り組んでおり、最高のJavaScriptエンジンを構築するために競い合っているため、さらに良くなるでしょう(すべての最新のエンジンが大量のJavaScript「インタープリタ」を行うのとは異なり、これはもはやJavaScript「インタープリタ」ではありません)。ジット内部でコンパイルし、解釈は 1 回限りのコードに対するフォールバックとしてのみ行います。ええ、私たちは皆、JavaScript 言語の奇妙な選択のいくつかを修正できればと思っていますが、実際にはそれほど悪くはありません。また、この言語は非常に柔軟なので、実際には JavaScript をコーディングしているのではなく、Step または jQuery をコーディングしていることになります。他のどの言語よりも、JavaScript ではライブラリがエクスペリエンスを定義します。Web アプリケーションを構築するには、とにかく JavaScript をかなり知っておく必要があるため、サーバー上で JavaScript を使用してコーディングすると、スキル セットの相乗効果が得られます。これにより、クライアント コードを書くのが怖くなくなりました。

また、JavaScriptが本当に嫌いなら、次のような構文糖を使うこともできます。コーヒースクリプトまたはJavaScriptコードを作成するものなら何でも、Google ウェブ ツールキット(GWT)。

JavaScript といえば、「クロージャ」とは何でしょうか? - 呼び出しチェーン全体でレキシカル スコープの変数を保持することを言い表した、かなりおしゃれな方法です。 ;) 次のようになります。

var myData = "foo";
database.connect( 'user:pass', function myCallback( result ) {
    database.query("SELECT * from Foo where id = " + myData);
} );
// Note that doSomethingElse() executes _BEFORE_ "database.query" which is inside a callback
doSomethingElse();

オブジェクトに格納するなどの面倒な操作を行わずに、「myData」を使用できることがわかります。また、Java とは異なり、「myData」変数は読み取り専用である必要はありません。この強力な言語機能により、非同期プログラミングの冗長性と手間が大幅に軽減されます。

非同期コードの作成は、単純なシングルスレッド スクリプトの作成よりも常に複雑になりますが、Node.js を使用すると、それほど難しくなく、数千の同時接続に対する効率性とスケーラビリティに加えて、多くの利点が得られます...

おすすめ記事