2012-04-24 1 views
2

今、私のtry/catchブロックがまったく動作するかどうかは、私にとって謎です。私はそれらをコードの周りに置いて、その後、コード内の何かがOSレベルで別のスレッド/プロセスにフォークされたと言う素晴らしい方法であると思われる「非同期」なので、try/catchは無視されますコード。Node.jsを使用すると、コードが現在のスタックを離れるときに私に教えてくれる意味がありますか?

私はそれでいいです、私はちょうどこれのいくつかの兆候があるかどうか知りたいですか?慣例では、コールがコールバックを要求すると、それはアシックです。それ以外の場合はそうではありません。私はなぜコールバックがasychを意味するのかを知るが、逆が常に真ではないことを恐れている:それは新しいコールスタックにロードされるtry/catchを使ってコールを囲むことから私を止めるものではないし、コールバック。これは本当に面倒なようですが、可能ならばすべての未捕捉例外が処理されるデフォルトのコールバックを使用するよりも、try/catchの方が少しは制御したいと思います。

  1. コードが の現在のスタックから離れるときの意味を教えてください。

UPDATEは:ここでの例である:それは別のコールスタックに起こるようにコード上で与えられた

var UserSchema = new mongoose.Schema({ 
    email: {type: String, unique: true}, 
    password: String, 
    firstName: String, 
    lastName: String, 
    created_at: {type: Date, default: Date.now}, 
    updated_at: Date 
}); 


var User = mongoose.model('User', UserSchema); 

var users = [ 
    {email: '[email protected]', firstName: 'Justin', lastName: 'Jones'}, 
    {email: '[email protected]', firstName: 'Justin', lastName: 'Jones'} 
]; 


users.forEach(function(user) { 

      var newUser = new User(user); 
      newUser.save(function(err, obj) { 

      if (!err) console.log("Saved: ", obj.email); 

      }); 

}); 

、、)(保存の内部例外をキャッチする方法はありません。私がsave()を呼び出すときに起こっていることを外部から知る方法はありますか?

更新:このためにハンドラを使用するように指示されている人は誰でも、thisと読むべきでしょうか?明らかに、「スレッド実行」で捕捉されていない例外を処理しないことを示唆しています。これはスレッドのようにしか動作しないためです。

+0

あなたは大きなものの代わりに3つの質問を書く必要があります。 – kay

+0

ありがとうございました。 –

+1

私はupvotesの欠如は、人々が完全にお互いに矛盾する、応答と議論のトンがあったので、戸惑うと主張するつもりです。それで、私はそれがかなり良い質問だと思った。 :P –

答えて

2

Nathan:「コードが現在のスタックを離れるとき」を見つけ出すという大きな問題には取り掛かりません。私はあなたのユーザーを節約してあなたを助けることができます。私は偉大なasyncライブラリをお勧めします:

function saveUser(user, callback) { 
    new User(user).save(callback); 
} 

async.forEach(users, saveUser, function(err, results) { 
    // Respond 
}); 
+1

これは私の質問に対する答えを知る必要なしに私の問題を処理します。 :) –

+0

それを聞いてうれしい! [async](https://github.com/caolan/async)ライブラリは、あらゆる種類のループ/フロー制御のために非同期コードで送信される神です。 node.jsのイベントループは、あなたの頭を包み込むのにしばらく時間がかかります。私の経験では、コーディングスタイルを受け入れるだけです。基本的に、名前付き関数はコード構造に役立ちます。また、 'err、result'をコールバックに渡すというnode.jsスタイルに固執することが賢明です。 'if(err)return next(err)'は、(通常はリクエストハンドラなどで)エラーを処理できる場所に来るまで、ほとんどのコールバックの最初の行です。 –

+0

*恥知らずの自己プラグ*:[私のこの回答](http://stackoverflow.com/questions/9362823/why-is-a-function-and-a-callback-non-blocking-in-node-js/ 9363071#9363071)は、イベントループの背後にある一般的な考え方を突き詰めるのに役立つことがあります。 –

2

意味は文字通り、あなたが呼び出した関数が実行を終了したときだけです。 I/Oプロセスを起動してイベントを登録すると、ブロックは、暗黙のJavascriptイベントループによって別のループで実行されるため、ブロックを囲みません。

実行中の関数でコールバックパラメータが存在するかどうかは、関数によって開始された作業によってイベントがどこかで発生するかどうかには何の影響もありません。 EventEmitter-based object.on('eventName', functionName)メカニズムでハンドラーを登録するため、複数のイベントと複数のハンドラーが同じ「作業」にアクセスできますが、すべてコールバックを必要としない関数によって開始されます。 ArrayオブジェクトのforEach methodはコールバックをとり、同期します。

イベントループのバリアを越えるものは、Javascript例外をスローするものではありません。物事のJavascript側のコードだけができます。したがって、必要に応じて、try-catchブロックをその側に置きます。非同期コードを呼び出す関数では、エラーが発生する可能性がある場合は非同期コードを呼び出し、エラーをスローする可能性のあるものをコールする場合はコールバック関数自体に呼び出します。非同期の場合、Javascriptの観点からは2つの別々の呼び出しスタックなので、異なるtry-catchスコープになります。同期している場合は、try-catchのチェックを1セット追加するだけです。少なくとも、エラーをスローした可能性のあるものがわかります。

私はtry-catchはJavascriptのような言語ではうまく動作せず、Javaのようにするために追加されたので、Node.jsにthrowというコードを使用しないようにしています。(例外は、動作できないライブラリ/オブジェクトの初期設定のためにのみ使用する場合、または深い同期コードから抜け出すための内部的な方法として、[実行オーバーヘッドのために]私の意見では、 。と)私に

EDITそれを公開していません:によってスローされます

== Javascript Event Loop ========================================================= 
== My Awesome Function ====================================== == My callback == 
    == Call to an async library ==================== 
     == I/O request and callback registration === 

何か:より良いJavaScriptでコールスタックを説明するために、ここでの時間に対するスタックの各レベルを示す簡単なASCII図ですMy callbackはJavascriptイベントループに直接送られ、その時点でそれを処理するためにprocess.on('uncaughtException', myFunc)ハンドラを登録することによってのみ捕まえることができます。基本的には、あなたのコードは確かにtry-catchを使うことができますが、それはイベントハンドラとして直接呼び出される場合は決してthrowにするべきではありません。

あなたの質問への最近の編集では、async.forEachがあなたの問題を解決します。反復する配列、配列の各項目で実行する関数、エラーを処理するか、そこからコードを続けるための "finally"スタイルの関数を渡します。

+0

本質的に、コールが独自のコールスタックで実行されるかどうかを外部から判断する方法はありませんか? –

+0

「投げる」、「試して」、「キャッチする」ということを明確にするためのダビデのアドバイスは基本的には健全です。代わりに、コールバックの最初のパラメータとしてエラーを渡すというnode.jsパラダイムを使用します。あなたがそれらを扱うことができるまで、コールチェーンの上にエラーを渡しておきます。基本的には、Javaなどで例外がどのようにバブルアップするのかと同じようにバブルアップさせます。 –

+0

この例では、save()メソッドの内部で何が起こるのかわからないので、この編集を実際に行う方法はありません。@ LinusGThielそれは常に実行の主要部分に持ち上げられることになります。 –

4

"非同期"はではありません。 "別のスレッド/プロセスにフォークされているという気の利いた方法"です。

JavaScriptはシングルスレッドです。物語の終わり。言語レベルではフォークはありません。

"非同期"とは、実行順序はコードの順序ではありません。コードコールバック関数のいくつかのビットは、特定のイベントが発生したある時点で実行されます。イベントベースのプログラミングモデルです。

は、この単純な例を考えてみましょう:

function hello() { alert("Hello!"); } 

setTimeout(hello, 2000); 

これは、その最も基本的な形での非同期コールバックです。コールバックハンドラ(関数hello)とイベントジェネレータ(この例では時間ベースのハンドラ)があります。

イベントが発生すると(2秒以上経過した)、コールバックハンドラが呼び出されます。

は今すぐ修正のために:

function hello() { alert(foo.bar); } 

try {  
    setTimeout(hello, 2000); 
} catch (ex) { 
    alert(ex.message); 
} 

我々はsetTimeout周りtry-catchブロックを紹介します。それはコールバックの登録、それ以上何も警備するものではありません。ほとんどの場合、このステップは成功します。したがってtry-catchブロックは決して何もしません。コールバックが2秒後に失敗するという事実は、try-catchブロックには当然影響しません。これはあなたが混乱していると思われる動作です。他の変形のための今

は:

function hello() { 
    try {  
    alert(foo.bar); 
    } catch (ex) { 
    alert("foo.bar is not defined"); 
    } 
} 

setTimeout(hello, 2000); 

try-catchブロックは、実際に失敗する可能性がありますステップを守ります。これは、エラーが発生する可能性のあるtry-catchブロックを使用する必要があることを意味します。通常、プログラムの大きな部分(これはあなたがやっているように見える)にはラップされません。

しかし、例外をどのようにして有用で設定可能なものにするのですか?より多くのコールバックを自然に導入することで、追加した例を1として


function hello(onError) { 
    try {  
    alert(foo.bar); 
    } catch (ex) { 
    onError("foo.bar is not defined", ex); 
    } 
} 

function errorHandler(customMessage, exception) { 
    alert(customMessage); 
    // or do something with exception 
} 

setTimeout(function() { 
    hello(errorHandler) 
}, 2000); 

var saveUsers = function(users, onSuccess, onError) { 
    users.forEach(function(user) { 
    var newUser = new User(user); 

    newUser.save(function(err, obj) { 
     if (err) { 
     onError(err, obj); 
     return false; 
     } else { 
     onSuccess(obj); 
     } 
    }); 
    }); 
} 

var users = [ 
    {email: '[email protected]', firstName: 'Justin', lastName: 'J'}, 
    {email: '[email protected]', firstName: 'Justin', lastName: 'J'} 
]; 

saveUsers(
    users, 
    function (user) { console.log("Saved: ", user.email); }, 
    function (err, user) { console.log("Could not save: ", user.email); } 
}); 
+0

これは、ボンネットの外部スレッドではないため、それと対話する識別可能な方法がない個別のコールスタックがある理由を説明しています。すみません、申し訳ありませんが、スレッドをまったく同じように動作するものは、ボンネットの下ではなく、try/catchのばかばかしいことを外部からキャッチすることはできません楽しい;)あなたが私の質問に答えなかったと言ったことすべて、あなたの例のどれもが私が意味していたものではありません。私は私の質問を編集し、1つ与える。 –

+0

技術的なノードは、厳密にはシングルスレッドではありません。なぜなら、私が理解する限り、いくつかのタスクのためにフードの下でスレッドを使用するからです。一般的には、non-blocking I/O呼び出しを達成するために 'epoll'などを使用しています。 – chesles

+2

@ Nathan私は、非同期の概念があなたを混乱させると信じています。 sarcsmの必要はありません(私はそれが非常に有用であるとは思わない)。 'try' /' catch'はそれがするべきことを正確に行うことができます。私はそれがあなたの方法になるあなたの "同期的な思考"だと信じています。少なくとも、HTTPリクエストなどの対話するものがJavaScript以外のスレッドとして実装されているかどうかは重要ではありません。それらはイベントを生成し、それがJSコードにとって重要なことです。物事があなたがそれらを期待する方法ではないという理由だけで、物事が間違っているということではありません。あなたの期待は間違っている可能性もあります。 – Tomalak

-1

あなたは、単にコールバック関数を使用している場合、それは問題ではありません。 NodeJSはシングルスレッドなので、すべてが同じコールスタックにあります。

BUT! NodeJSが現在のコールスタックを「離れる」ことがあります。休暇は現在のコールスタックを離れずに単にルートコール(process.nextTick())に戻っているため、引用符で囲まれています。次のティックでは、それは "新しい"コールスタックを生成します。

意味が必要な場合は、EventEmitterを使用している場所であれば、そのコールバック関数を次のティックに渡し、別のコールスタックに「移動」していると言えるでしょう。 EventEmitterは実際には現在のチックでイベントを送出するため、実際はそうではありません。

+0

これは正確には当てはまりませんが、コールバック関数を使用しても問題がなければ、キャッチされない例外が発生した場合はコールバックが起こりません。 –

+1

これはせいぜい混乱しており、 "すべてが同じ呼び出しスタックにある"という主張は単に間違っています。 – josh3736