2010-12-05 7 views
18

私は経験豊富なソフトウェア開発者ですが、JSやノードにとってはかなり新しいです。私はスーパーネストされたコードの大ファンではないので、コールバックを自分の関数に分解しようとしています。コールバックが発生したときにスコープを維持する方法を考えても問題はあります。周りを掘り起こすコールバックでクロージャを作成してもうまくいくとは思っていましたが、期待通りに動作していないようです。node.jsコールバックでどのようにスコープを維持できますか?

ここでは私のために働いていないコードの種類の非常にシンプルなバージョンです:私は、関数内writeBody()の呼び出し()の閉鎖をラップすることにより、私はスコープを持っているだろうと思った

function writeBody() 
{ 
    res.end("<h1> Hooray! </h1>"); 
} 

http.createServer(function(req, res) 
{ 
    res.writeHead('Content-Type', 'text/html'); 
    setTimeout(function(){writeBody()}, 2000); 
}).listen(8000); 

私は、タイムアウト後に必要に応じて、しかしときwriteBody()は私が

ReferenceError: res is not defined

は、誰もが私が間違っているのboneheaded何の事を教えてもらえます取得発射しますか?

答えて

35

基本的には、クロージャの仕組みが機能していないので、関数はその外側のスコープを継承します。

// this function only inherits the global scope 
function writeBody() 
{ 
    res.end("<h1> Hooray! </h1>"); 
} 

http.createServer(function(req, res) // a new local varaible res is created here for each callback 
{ 
    res.writeHead('Content-Type', 'text/html'); 
    // annonymous function inheris both the global scope 
    // as well as the scope of the server callback 
    setTimeout(function(){ 

     // the local variable res is available here too 
     writeBody() 

    }, 2000); 
}).listen(8000); 

それがタイムアウトコールバックで利用できるようちょうど、関数にresオブジェクトを渡す動作させるために。

function writeBody(res) 
{ 
    // NOT the same variable res, but it holds the same value 
    res.end("<h1> Hooray! </h1>"); 
} 

http.createServer(function(req, res) 
{ 
    res.writeHead('Content-Type', 'text/html'); 
    setTimeout(function(){ 
     writeBody(res); // just pass res 
    }, 2000); 
}).listen(8000); 

しかし、あなたはこのようなことに注意する必要があります。

for(var i = 0; i < 10; i++) { // only one i gets created here!() 
    setTimeout(function() { 
     console.log(i); // this always references the same variable i 
    }, 1000); 
} 

参照が同じであるとiはすべての方法10までインクリメントされますので、これは、10 10回を印刷します。異なる番号を持つ場合は、setTimeoutをパラメータとしてiに渡す匿名のself関数にラップするか、またはtimouetを設定する他のメソッドを呼び出して、それぞれの変数を作成する必要がありますパラメータとしてiを受信します。

// anoynmous function version 
for(var i = 0; i < 10; i++) { 
    (function(e){ // creates a new variable e for each call 
     setTimeout(function() { 
      console.log(e); 
     }, 1000); 
    })(i); // pass in the value of i 
} 

// function call version 
for(var i = 0; i < 10; i++) { 
    createTimeoutFunction(i); 
} 
+0

ああ!ダー! * facepalm *それはトンを助けます、私はちょうど私の脳の中でシフト - アイの瞬間を持っていた。 – MahatmaManic

2

私は、多くの場合、それは意味が、これは、常にスコープに保つための変数の束を渡すよりも簡単です見つけるあなたはまた、関数が入れ子にすることができますので、彼らはスコープを共有する、すなわち

http.createServer(function(req, res) 
{ 

    function writeBody() 
    { 
     res.end("<h1> Hooray! </h1>"); 
    } 

    res.writeHead('Content-Type', 'text/html'); 
    setTimeout(function(){writeBody()}, 2000); 
}).listen(8000); 

他の場所で関数を再利用することはできません。

+1

私はあなたの答えに時間を割いていただき、ありがとうございます。あなたはおそらく、それがしばしばより早くて簡単だと思います。しかし、スタイルの一般的なルールとして、私はできる限りネスティングを避けようとしています。この単純な例では、それほど悪くはありませんが、物事が複雑になると(ファイルの検索、読み取り、処理など)、醜い速度になります。 – MahatmaManic

+0

私はこのスタイルが好きです。この概念を拡張した回答を掲載しました。 – rocketsarefast

0

あなたはとてもあなたのコールバックでの応答を渡すことができます。

http.createServer(function(req, res) 
{ 
    res.writeHead('Content-Type', 'text/html'); 
    setTimeout(function(){writeBody(res)}, 2000); 
}).listen(8000); 
0

I実際にジャスティン・コーマックの答えのような。ここ最近の私のコーディングのもっと極端な例があります。

var Func4 = function(req, res) 
{ 
    var collectionName = "parts"; 
    var f0 = function() {mongodbClient.collection(collectionName, f1);}; 
    var f1 = function(err, coll) {coll.ensureIndex("item", f2);}; 
    var f2 = function(err, indexname) 
    { 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.write("index name = " + indexname); 
    res.end(); 
    }; 
    f0(); 
}; 

これは、このコードを記述するのが正しい方法であると私に教えてくれます。

var Func4 = function(req, res) 
{ 
    var collectionName = "parts"; 
    mongodbClient.collection(collectionName, function(err, coll) { 
    coll.ensureIndex("item", function(err, indexname) { 
     res.writeHead(200, {'Content-Type': 'text/plain'}); 
     res.write("index name = " + indexname); 
     res.end(); 
    })}); 
}; 

おそらく私はn00bですが、ネストされたコールバックが少し難しいと感じています。私はまたf0、f1、f2関数の束が不自由であることを認めます。いずれにせよ、これは範囲の良い例です。

関連する問題