著者からのコメント
この記事は新しいものですが、新機能に関するものではありません。 それは中核、つまりプラットフォームに関するものであり、単にうなり声やwebpackを単に使用する多くの人が疑わないかもしれないという事実についてです。
詳細を読む:
ラムキンのコメント:
habrahabr.ru/company/mailru/blog/283228/#comment_8890604
アイディッツのコメント:
habrahabr.ru/company/mailru/blog/283228/#comment_8890476
Suvitrufコメント:
habrahabr.ru/company/mailru/blog/283228/#comment_8890430
この投稿のアイデアは、Kyle Simpsonの一連の書籍「 You Do n't Know JavaScript 」に触発されました。 彼らはこの言語の基礎を学ぶ良いスタートです。 Nodeは、この記事で説明する小さな違いを除いて、ほぼ同じJavaScriptです。 以下のすべてのコードは、 リポジトリから
code
フォルダーからダウンロードできます。
Nodeに煩わされるのはなぜですか? NodeはJavaScriptであり、JavaScriptはほぼすべての場所で使用されています! 開発者の大多数がNodeを完全にマスターすれば、世界は良くなるでしょう。 より良いアプリケーション、より良い生活!
この記事は、Nodeの最も興味深いコア機能の現実的な外観です。 記事のキーポイント:
- イベントループ:ノンブロッキングI / Oを実装するための重要な概念の更新
- グローバルオブジェクトとプロセス:詳細情報の取得方法。
- イベントエミッター:イベントベースのパターンの集中的な紹介
- ストリームとバッファ:データを操作する効率的な方法
- クラスター:プロのようなフォークプロセス
- 非同期エラー処理: AsyncWrap、Domain、およびuncaughtException
- C ++のアドオン:カーネルで独自の開発を行い、C ++で独自のアドオンを作成する
イベントループ
Nodeの基礎となるイベントループから始めましょう。
Node.jsの非ブロッキングI / O
このサイクルにより、I / O操作の実行と並行して他のタスクを操作できます。 NginxとApacheを比較してください。 I / Oのブロックは安くないため、Nodeは非常に高速で効率的です。イベントループのおかげです。
Javaで保留中の
println
関数のこの単純な例を見てください。
System.out.println("Step: 1"); System.out.println("Step: 2"); Thread.sleep(1000); System.out.println("Step: 3");
これはNodeコードに匹敵します(完全ではありませんが):
console.log('Step: 1') setTimeout(function () { console.log('Step: 3') }, 1000) console.log('Step: 2')
これは同じではありません。 非同期操作の観点から考え始めます。 Nodeスクリプトの出力は1、2、3です。 しかし、「ステップ2」の後にさらに式があれば、最初にそれらが実行され、それから
setTimeout
関数のコールバックが実行されます。 このスニペットを見てください:
console.log('Step: 1') setTimeout(function () { console.log('Step: 3') console.log('Step 5') }, 1000); console.log('Step: 2') console.log('Step 4')
彼の作業の結果はシーケンス
setTimeout
ます。理由は、
setTimeout
がイベントループの将来の期間にコールバックを配置するためです。
イベントループは、
for … while
ような無限ループと考えることができます。 彼は、現在も将来も、何もすることがないときにだけ立ち止まります。
ブロッキングI / O:マルチスレッドJava
イベントループにより、システムはより効率的に動作し、アプリケーションは高価なI / O操作の完了を待っている間に他のことを行うことができます。
Node.jsの非ブロッキングI / O
これは、オペレーティングシステムのスレッドを使用するより一般的な同時実行モデルとは対照的です。 ネットワークフローモデル(スレッドベースのネットワーク)は非常に非効率的で、使用が非常に困難です。 さらに、Nodeユーザーはプロセスを完全にブロックすることを恐れないかもしれません-ここにはロックがありません。
ところで、Node.jsでは、ブロッキングコードを作成できます。 この簡単なスニペットを見てください。
console.log('Step: 1') var start = Date.now() for (var i = 1; i<1000000000; i++) { // This will take 100-1000ms depending on your machine } var end = Date.now() console.log('Step: 2') console.log(end-start)
もちろん、通常、コードには空のループはありません。 他の人のモジュールを使用する場合、同期を検出することがより困難になる可能性があります。つまり、コードをブロックします。 たとえば、メインモジュール
fs
(ファイルシステム)には2つのメソッドセットが付属しています。 各ペアは同じことを行いますが、方法は異なります。
fs
モジュールのブロックメソッドには、名前に
Sync
という単語が含まれています。
var fs = require('fs') var contents = fs.readFileSync('accounts.txt','utf8') console.log(contents) console.log('Hello Ruby\n') var contents = fs.readFileSync('ips.txt','utf8') console.log(contents) console.log('Hello Node!')
このコードの実行結果は、Node / JavaScriptの初心者でも完全に予測可能です。
data1->Hello Ruby->data2->Hello NODE!
しかし、非同期メソッドに切り替えると、すべてが変わります。 ノンブロッキングコードの例を次に示します。
var fs = require('fs'); var contents = fs.readFile('accounts.txt','utf8', function(err,contents){ console.log(contents); }); console.log('Hello Python\n'); var contents = fs.readFile('ips.txt','utf8', function(err,contents){ console.log(contents); }); console.log("Hello Node!");
実行には時間がかかるため、
contents
は最後に表示され、コールバックにも含まれます。 ファイルを読み取った後、イベントループがそれらに移動します。
Hello Python->Hello Node->data1->data2
一般に、イベントループとノンブロッキングI / O操作は非常に強力ですが、多くは慣れていない非同期コードを記述する必要があります。
グローバルオブジェクト
開発者がブラウザベースのJavaScriptまたは別の言語からNode.jsに切り替える場合、次の質問があります。
- パスワードを保存する場所は?
- グローバル変数を作成する方法(ノードには
window
がありません)? - CLI入力、OS、プラットフォーム、メモリ、バージョンなどにアクセスする方法は?
これを行うには、特定のプロパティを持つグローバルオブジェクトがあります。 それらのいくつかを次に示します。
-
global.process
:プロセス、システム、環境情報(CLI入力データ、パスワード付きの環境変数、メモリなどを参照できます) -
global.__filename
:ファイル名と、この式が置かれている現在実行中のスクリプトへのパス。 -
global.__dirname
:現在実行中のスクリプトへのフルパス。 -
global.module
:このファイルからモジュールを作成するコードをエクスポートするオブジェクト。 -
global.require()
:モジュール、JSONファイルおよびフォルダーをインポートするためのメソッド。
よくある疑いもあります-ブラウザJavaScriptのメソッド:
-
global.console()
-
global.setInterval()
-
global.setTimeout()
各グローバルプロパティには、
global.process
代わりに
global.process
記述
process
だけで、大文字で入力された名前
GLOBAL
、または名前をまったく付けずにアクセスできます。
プロセス
プロセスオブジェクトには多くの情報が含まれているため、別の章に値します。 以下にそのプロパティの一部を示します。
-
process.pid
:このNodeインスタンスのプロセスID。 -
process.versions
:Node、V8、およびその他のコンポーネントの異なるバージョン -
process.arch
:システムアーキテクチャ -
process.argv
:CLI引数 -
process.env
:環境変数
いくつかの方法:
-
process.uptime()
:作業時間を取得します -
process.memoryUsage()
:消費されるメモリ量を取得します -
process.cwd()
:現在の作業フォルダーを取得します。 プロセスが起動された場所に依存しない__dirname
と混同__dirname
ないでください。 -
process.exit()
:現在のプロセスを終了します。 たとえば、コード0または1を渡すことができます。 -
process.on()
:イベントにアタッチします。たとえば、 `on( 'uncaughtException')
難しい質問:誰が好きで、誰がコールバックの本質を理解していますか?
誰かが彼らと「恋をしている」ため、彼はhttp://callbackhell.comを作成しました。 この用語がよくわからない場合は、次の図をご覧ください。
fs.readdir(source, function (err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } })
コールバック地獄は読みづらく、ここで間違いを犯すことは簡単です。 それでは、コールバックを使用しない場合、開発の観点からのスケーリングにはあまり便利ではないのに、どのようにモジュールに分割し、非同期コードを整理しますか。
イベントエミッター
イベントエミッターは、コールバックの地獄、または運命のピラミッドに対処するために使用されます。 彼らの助けを借りて、イベントを使用して非同期コードを実装できます。
要するに、イベントエミッタは、誰でも聞くことができるイベントのトリガーです。 Node.jsでは、イベントごとに、エミッターがコールバックをハングできる文字列名が割り当てられます。
エミッターとは:
- Nodeでは、イベントはオブザーバーパターンを使用して処理されます。
- イベント(またはサブジェクト)は、それに関連するすべての機能を追跡します。
- これらの関数—オブザーバー—は、このイベントがアクティブになると実行されます。
エミッタを使用するには、モジュールをインポートし、オブジェクトのインスタンスを作成する必要があります。
var events = require('events') var emitter = new events.EventEmitter()
次に、イベントレシーバーを接続し、イベントをアクティブ化/送信できます。
emitter.on('knock', function() { console.log('Who\'s there?') }) emitter.on('knock', function() { console.log('Go away!') }) emitter.emit('knock')
EventEmitter
使用して、彼から継承して有用なこと
EventEmitter
しましょう。 月ごと、週ごと、または毎日、クラスを定期的に実装する必要があるとします。 このクラスは、他の開発者が最終結果をカスタマイズできるように十分な柔軟性が必要です。 つまり、作業の最後に、誰でもクラスに何らかのロジックを配置できる必要があります。
この図は、イベントモジュールからの継承を使用して
Job
作成し、
done
イベントレシーバーを使用して
Job
クラスの動作を変更する方法を示しています。
Node.jsのイベントエミッター:オブザーバーパターン
Job
クラスはそのプロパティを保持しますが、同時にイベントを受け取ります。 プロセスの最後で、
done
イベントを起動するだけです。
// job.js var util = require('util') var Job = function Job() { var job = this // ... job.process = function() { // ... job.emit('done', { completedOn: new Date() }) } } util.inherits(Job, require('events').EventEmitter) module.exports = Job
最後に、
Job
の動作を変更します。
done
を渡すと、イベントレシーバーをアタッチできます。
// weekly.js var Job = require('./job.js') var job = new Job() job.on('done', function(details){ console.log('Job was completed at', details.completedOn) job.removeAllListeners() }) job.process()
エミッタには他の可能性があります:
-
emitter.listeners(eventName)
:このイベントのすべての受信者のリストを形成します。 -
emitter.once(eventName, listener)
イベント名emitter.once(eventName, listener)
:ワンタイムイベントレシーバーをアタッチします。 -
emitter.removeListener(eventName, listener)
:イベントレシーバーを削除します。
Nodeはどこでも、特にメインモジュールでイベントパターンを使用します。 したがって、イベントを正しく使用すれば、時間を大幅に節約できます。
ストリーム
Nodeで大量のデータを扱う場合、いくつかの問題があります。 パフォーマンスが低下する場合があり、バッファサイズは約1 GBに制限されます。 さらに、決して終わらないという期待を持って作成された無限のリソースで作業する方法は? このような状況では、ストリームが役立ちます。
Nodeのストリームは抽象化であり、データをフラグメントに連続的に分割することを示します。 つまり、リソースが完全にロードされるのを待つ必要はありません。 この図は、バッファリングの標準的なアプローチを示しています。
Node.jsのバッファリングアプローチ
データの処理や出力を開始する前に、バッファが完全にロードされるまで待つ必要があります。 次に、これをフローチャートと比較します。 この場合、最初のチャンクを取得するとすぐに、データの処理および/または出力をすぐに開始できます。
Node.jsでのストリームアプローチ
Nodeには4つのタイプのストリームがあります:
- 読み取り可能:それらから読み取ることができます。
- 書き込み可能:それらに書き込むことができます。
- 二重:書き込みと読み取りができます。
- 変換:データの変換に使用できます。
事実上、ストリームはNodeのあらゆる場所で使用されます。 最も人気のあるストリームの実装:
- HTTPリクエストとレスポンス。
- 標準入出力操作。
- ファイルの読み取りと書き込み。
オブザーバーパターンを提供するために、ストリーム—イベント—は、イベントエミッタオブジェクトから継承します。 これを使用して、ストリームを実装できます。
読み取り可能なストリームの例
例は、標準入力ストリームである
process.stdin
です。 これには、アプリケーションに入るデータが含まれています。 これは通常、プロセスを開始するために使用されるキーボード情報です。
data
および
end
イベントは、
stdin
からデータを読み取るために使用されます。
data
イベントのコールバックには、引数として
chunk
があります。
process.stdin.resume() process.stdin.setEncoding('utf8') process.stdin.on('data', function (chunk) { console.log('chunk: ', chunk) }) process.stdin.on('end', function () { console.log('--- END ---') })
次に、
chunk
入力としてプログラムに送られます。 このイベントは、着信情報の合計量に応じて、数回アクティブ化できます。 ストリームの完了は、
end
イベントを使用して通知する必要があります。
注:
stdin
はデフォルトで一時停止されています
stdin
からデータを読み取る前に
stdin
出力する必要があります。
読み取り可能なストリームには、同期的に動作する
read()
インターフェイスがあります。 ストリームの最後で、
chunk
または
null
返し
null
。
while
条件で
null !== (chunk = readable.read())
コンストラクトを設定することにより、この動作を利用でき
null !== (chunk = readable.read())
var readable = getReadableStreamSomehow() readable.on('readable', () => { var chunk while (null !== (chunk = readable.read())) { console.log('got %d bytes of data', chunk.length) } })
理想的には、スレッドのブロックを回避するために、できるだけ頻繁にNodeに非同期コードを記述したいと考えています。 ただし、チャンクのサイズが小さいので、スレッドをブロックする同期的
readable.read()
を心配する必要はありません。
記録されたストリームの例
例は、標準出力ストリームである
process.stdout
です。 アプリケーションを離れるデータが含まれています。
write
操作を使用してストリームに書き込むことができます。
process.stdout.write('A simple message\n')
console.log()
を使用したかのように、標準出力ストリームに記録されたデータがコマンドラインに表示されます。
パイプ
Nodeには、上記のイベントの代わりに
pipe()
メソッドがあります。 次の例では、ファイルからデータを読み取り、GZipを使用して圧縮し、結果をファイルに書き込みます。
var r = fs.createReadStream('file.txt') var z = zlib.createGzip() var w = fs.createWriteStream('file.txt.gz') r.pipe(z).pipe(w)
Readable.pipe()
はデータストリームを受け取り、すべてのストリームを通過するため、
pipe()
メソッドからチェーンを作成できます。
そのため、ストリームを使用する場合、イベントまたはパイプを使用できます。
HTTPストリーム
私たちのほとんどはNodeを使用してWebアプリケーションを作成します。従来の(サーバー側)またはREST APIに基づいています(クライアント側)。 HTTPリクエストはどうですか? ストリーミングできますか? 間違いなく!
要求と応答は、イベントエミッターから継承された読み取りおよび書き込みストリームです。
data
イベントレシーバーを接続し、コールバックで
chunk
を受け入れることができます。
chunk
は、応答全体を待たずにすぐに変換できます。 次の例では、
body
を連結し、
end
イベントのコールバックに解析します。
const http = require('http') var server = http.createServer( (req, res) => { var body = '' req.setEncoding('utf8') req.on('data', (chunk) => { body += chunk }) req.on('end', () => { var data = JSON.parse(body) res.write(typeof data) res.end() }) }) server.listen(1337)
注:ES6によると、
()=>{}
は匿名関数の新しい構文であり、
const
は新しい演算子です。 ES6 / ES2015の機能と構文にまだ慣れていない場合は、 忙しいJavaScript開発者が知っておくべきES6プロパティに関するトップ10の記事をご覧ください 。
次に、Express.jsを使用して、サーバーを実際の生活から離さないようにします。 巨大な画像(約8 MB)と2組のExpressルート
/stream
および
/non-stream
。
server-stream.js:
app.get('/non-stream', function(req, res) { var file = fs.readFile(largeImagePath, function(error, data){ res.end(data) }) }) app.get('/stream', function(req, res) { var stream = fs.createReadStream(largeImagePath) stream.pipe(res) })
また、イベントを使用した
/stream2
代替実装と、
/non-stream2
同期実装もあります。 それらは同じことをしますが、異なる構文とスタイルを使用します。 この場合、複数の競合するリクエストではなく、1つのリクエストのみを送信するため、同期メソッドの方が高速です。
ターミナルからこのコードを実行できます。
$ node server-stream
次に、Chrome http:// localhost:3000 / streamおよびhttp:// localhost:3000 / non-streamで開きます 。
X-Response-Time
比較して、開発者ツールの[ネットワーク]タブのヘッダーに注目してください。 私の場合、
/stream
と
/stream2
は、桁違いに300ミリ秒異なりました。 3-5秒 値が異なる場合もありますが、考え方は明確です。/streamの場合
/stream
ユーザー/クライアントはより早くデータを受信し始めます。 Nodeでのストリーミングは非常に強力なツールです! チームのこの分野の専門家になることで、ストリームリソースを適切に管理する方法を学ぶことができます。
npmを使用すると、 Stream Handbookとstream-adventureをインストールできます。
$ sudo npm install -g stream-adventure $ stream-adventure
バッファ
バイナリデータにはどの型を使用できますか? 覚えていれば、JavaScriptブラウザーにはバイナリデータ型はありませんが、Nodeにはあります。 これはバッファと呼ばれます。 これはグローバルオブジェクトなので、モジュールとしてインポートする必要はありません。
次の式のいずれかを使用して、バイナリタイプを作成できます。
-
new Buffer(size)
-
new Buffer(array)
-
new Buffer(buffer)
-
new Buffer(str[, encoding])
メソッドとエンコーディングの完全なリストは、 バッファのドキュメントで入手できます 。 最も一般的に使用される
utf8
エンコーディング。
通常、バッファの内容はちらつきのように見えるので、人が読めるようにするには、まず
toString()
を使用して文字列表現に変換する必要があります。
for
ループを使用してアルファベットでバッファを作成
for
ます。
let buf = new Buffer(26) for (var i = 0 ; i < 26 ; i++) { buf[i] = i + 97 // 97 is ASCII a }
バッファを文字列表現に変換しない場合、数値の配列のようになります。
console.log(buf) // <Buffer 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a>
変換を実行します。
buf.toString('utf8') // outputs: abcdefghijklmnopqrstuvwxyz buf.toString('ascii') // outputs: abcdefghijklmnopqrstuvwxyz
文字列の一部(サブ文字列)のみが必要な場合、メソッドは目的のセグメントの初期番号と最終位置を取得します。
buf.toString('ascii', 0, 5) // outputs: abcde buf.toString('utf8', 0, 5) // outputs: abcde buf.toString(undefined, 0, 5) // encoding defaults to 'utf8', outputs abcde
fs
覚えていますか? デフォルトでは、
data
もバッファーです。
fs.readFile('/etc/passwd', function (err, data) { if (err) return console.error(err) console.log(data) });
data
は、ファイルを操作するときにバッファーとして機能します。
クラスター
Nodeの反対者は、スレッドが1つしかないため、スケーリングできるとしばしば主張します。 ただし、メイン
cluster
モジュールを使用すると(インストールする必要はありません。これはプラットフォームの一部です)、任意のマシンのすべてのプロセッサリソースを使用できます。 つまり、クラスターのおかげで、Nodeアプリケーションを垂直方向にスケーリングできます。
コードは非常に簡単です。モジュールをインポートし、1つのマスターと複数のワーカーを作成します。 通常、CPUごとに1つのプロセスを作成しますが、これは揺るぎない規則ではありません。 必要な数のプロセスを実行できますが、収益性を低下させる法律に従って、特定の時点から生産性の成長が停止します。
マスターコードと従業員コードは1つのファイルにあります。 従業員は、イベントをマスターに送信することにより、同じポートでリッスンできます。 ウィザードはイベントをリッスンし、必要に応じてクラスターを再起動できます。 ウィザードでは
cluster.isMaster()
れ、ワーカーで
cluster.isMaster()
ます。 ほとんどのサーバーコードはワーカー(
isWorker()
)に配置されます。
// cluster.js var cluster = require('cluster') if (cluster.isMaster) { for (var i = 0; i < numCPUs; i++) { cluster.fork() } } else if (cluster.isWorker) { // })
この例では、サーバーがプロセスIDを発行するため、さまざまなワーカーがさまざまな要求を処理する方法を確認できます。 ロードバランサーのように見えますが、負荷は均等に分散されないため、これは単なる印象です。 たとえば、PIDにより、プロセスの1つがより多くの要求を処理する方法を確認できます。
, ,
loadtest
Node:
-
loadtest
npm: $ npm install -g loadtest
-
code/cluster.js
node ($ node cluster.js
); . - :
$ loadtest http://localhost:3000 -t 20 -c 10
. -
loadtest
. - Ctrl+C. PID.
loadtest
-t 20 -c 10
, 10 20 .
— , . , . :
-
strong-cluster-control
(https://github.com/strongloop/strong-cluster-control)$ slc run
-
pm2
(https://github.com/Unitech/pm2)
pm2
pm2
, Node-. ,
pm2
production.
pm2
:
- .
- , .
- .
https://github.com/Unitech/pm2 http://pm2.keymetrics.io .
pm2 -
server.js
. ,
isMaster()
, ,
cluster
.
pid
.
var express = require('express') var port = 3000 global.stats = {} console.log('worker (%s) is now listening to http://localhost:%s', process.pid, port) var app = express() app.get('*', function(req, res) { if (!global.stats[process.pid]) global.stats[process.pid] = 1 else global.stats[process.pid] += 1; var l ='cluser ' + process.pid + ' responded \n'; console.log(l, global.stats) res.status(200).send(l) }) app.listen(port)
pm2 start server.js
. /, (
-i 0
, , , 4).
-l log.txt
:
$ pm2 start server.js -i 0 -l ./log.txt
, pm2 . :
$ pm2 list
loadtest
,
cluster
. :
$ loadtest http://localhost:3000 -t 20 -c 10
,
log.txt
- :
cluser 67415 responded { '67415': 4078 } cluser 67430 responded { '67430': 4155 } cluser 67404 responded { '67404': 4075 } cluser 67403 responded { '67403': 4054 }
Spawn, Fork Exec
cluter.js
Node-
fork()
. , Node.js :
spawn()
,
fork()
exec()
.
child_process
. :
-
require('child_process').spawn()
: ; stream'; ; V8. -
require('child_process').fork()
: V8 ; Node.js (node
). -
require('child_process').exec()
: , ; , callback'; ,node
.
:
node program.js
, — bash, Python, Ruby .. , ,
spawn()
.
data
stream':
var fs = require('fs') var process = require('child_process') var p = process.spawn('node', 'program.js') p.stdout.on('data', function(data)) { console.log('stdout: ' + data) })
node program.js
,
data
, , .
fork()
spawn()
, : ,
fork()
, Node.js:
var fs = require('fs') var process = require('child_process') var p = process.fork('program.js') p.stdout.on('data', function(data)) { console.log('stdout: ' + data) })
,
exec()
. , , callback. error, standard output :
var fs = require('fs') var process = require('child_process') var p = process.exec('node program.js', function (error, stdout, stderr) { if (error) console.log(error.code) })
error
stderr
,
exec()
(,
program.js
), — (,
program.js
).
Node.js
try/catch
. .
try { throw new Error('Fail!') } catch (e) { console.log('Custom Error: ' + e.message) }
, . Java Node. Node.js , thread.
, , /. , .
,
setTimeout()
, callback'. , HTTP-, :
try { setTimeout(function () { throw new Error('Fail!') }, Math.round(Math.random()*100)) } catch (e) { console.log('Custom Error: ' + e.message) }
callback ,
try/catch
. , callback
try/catch
, , . .
try/catch
.
, . ? , callback'
error
. : callback' .
if (error) return callback(error) // or if (error) return console.error(error)
:
- (on error).
-
uncaughtException
. -
domain
( ) AsyncWrap . - .
- ( ).
- .
on('error')
on('error')
, Node.js,
http
.
error
, Express.js, LoopBack, Sails, Hapi ..,
http
.
js server.on('error', function (err) { console.error(err) console.error(err) process.exit(1) })
uncaughtException
uncaughtException
process
!
uncaughtException
— . , — Node.js — .
An unhandled exception means your application – and by extension Node.js itself – is in an undefined state. , .
process.on('uncaughtException', function (err) { console.error('uncaughtException: ', err.message) console.error(err.stack) process.exit(1) })
または
process.addListener('uncaughtException', function (err) { console.error('uncaughtException: ', err.message) console.error(err.stack) process.exit(1)
ドメイン
domain
. Node.js . , . :
domain
callback'
run()
:
var domain = require('domain').create() domain.on('error', function(error){ console.log(error) }) domain.run(function(){ throw new Error('Failed!') })
4.0
domain
, Node . Node
domain
. , ,
domain
npm-, npm.
domain
.
setTimeout()
:
// domain-async.js: var d = require('domain').create() d.on('error', function(e) { console.log('Custom Error: ' + e) }) d.run(function() { setTimeout(function () { throw new Error('Failed!') }, Math.round(Math.random()*100)) });
!
domain
error
“Custom Error”, Node .
C++
Node , IoT, , , /++. /++ ?
. Node , ++! , .
hello.cc
, . , .
#include <node.h> namespace demo { using v8::FunctionCallbackInfo; using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, "capital one")); // String } void init(Local<Object> exports) { NODE_SET_METHOD(exports, "hello", Method); // Exporting } NODE_MODULE(addon, init) }
, , , JavaScript.
capital one
:
args.GetReturnValue().Set(String::NewFromUtf8(isolate, "capital one"));
hello
:
void init(Local<Object> exports) { NODE_SET_METHOD(exports, "hello", Method); }
hello.cc
, .
binding.gyp
, :
{ "targets": [ { "target_name": "addon", "sources": [ "hello.cc" ] } ] }
binding.gyp
hello.cc
, node-gyp :
$ npm install -g node-gyp
,
hello.cc
binding.gyp
, :
$ node-gyp configure $ node-gyp build
build
.
build/Release/
.node
. , Node.js
hello.js
, C++:
var addon = require('./build/Release/addon') console.log(addon.hello()) // 'capital one'
capital one
, :
$ node hello.js
C++ : https://github.com/nodejs/node-addon-examples .
おわりに
GitHub . Node.js, callback' Node-, Node: callback' observer' .
:
- : , / Node.
- : .
- : “observer” Node.js.
- : .
- : .
- : .
- Domain: .
- C++: .
Node JavaScript, , , , . , Node.js.