2016-06-24 16 views
0

クラスコンストラクタからコールしている関数のコールバックからクラスメンバ変数を設定しようとしています。コールバックからクラスメンバ変数を設定できません

もう少し具体的には、Redis INCRの結果に基づいてConnectionクラスのコンストラクタに接続IDを設定する必要があります(複数のノードを持つことができるように、各クライアントには「グローバル」接続IDがあります)。

ここにコードがあります。

class Connection { 
    constructor() { 
    client.incr('conn_id', (err, reply) => { 
     this.connID = reply; 
    }); 
    } 
} 

var lovely = new Connection(); 
console.log(`lovely connID is ${ lovely.connID }`); 

これが結果です:lovely connID is undefined

+3

Redisに詳しいわけではありませんが、 'client.incr'は非同期ですか?つまり、client.incrへのコールバックが実行される前に、console.log行を実行している可能性があります。 – rom99

+0

http:// stackoverflowを参照してください。com/questions/34959257/why-isnt-my-future-value-available-now。 –

+0

あなたの問題は、 "クラスメンバー変数をコールバックから設定できません"が、 "設定前にクラスメンバー変数にアクセスできません"ということではありません。 –

答えて

-2

あなたが同じオブジェクトを参照しない場合がありますコールバック内thisを使用しています。コンテキストオブジェクトをclient.incr()のパラメータとして設定できる場合は、そのようにしてください。それ以外の場合はselfを使用すると、周りに行くための一般的な方法の一つである:

class Connection { 
    constructor() { 
    var self = this // Keep a reference to the current "this" 
    client.incr('conn_id', (err, reply) => { 
     self.connID = reply; 
    }); 
    } 
} 
+0

そのため、太い矢印表記が存在します。ここでの問題は、@ rom99がすでにコメントしているように、 'client.incr()'コールの非同期性です。 – robertklep

0

client.incr(「conn_idが」....)コールバックはあなたのコードの実行後に呼び出されることを意味非同期、と思われます。

ので

にconsole.log(lovely connID is ${ lovely.connID })。コールバックの前に呼び出されます。

(エラー、返信)=> { self.connID = reply; }これに似て

:これはここで他の人のよう

未定義 をvalue1

+0

確かに、彼はそれをどのように修正すべきですか? –

+0

ログを記録する必要がある場合は、コールバックの中でそれを行う必要があり、コールバックの中で関数を呼び出すことができる場合は –

+0

私は自分自身を求めていませんでした。私はあなたの答えがこの部分を欠いていたことを示唆しており、増幅されるべきです。コンストラクタ内部からのログはそれほど大きくありません。コンストラクタの外部からログを記録する場合はどうすればよいですか? –

0

を発生します実行している

class Connection{ 
    constructor(){ 
    self=this; 
    setTimeout(function(){self.client='somevalue'; 
          console.log('value1');}, 10) 

    } 
} 

var a = new Connection(); 

console.log(a.client); 

が言及している、問題はいるようですつまり、client.incrは非同期であり、 rコードはプロパティにアクセスする前に解決するのを待っていません。この問題を解決するには、にonReadyコールバックを渡して、アクセスしようとする前にプロパティが存在することを確認してください。これらの線に沿って何か:

'use strict'; 
 

 
// mock client.incr 
 
var client = { incr: (id, callback) => { 
 
    setTimeout(() => callback(null, 'Hello World'), 0) 
 
}}; 
 

 
class Connection { 
 
    // receive an "onReady" function 
 
    constructor(onReady) { 
 
    client.incr('conn_id', (err, reply) => { 
 
     this.connID = reply; 
 
     // call "onReady" function, and pass it the class 
 
     if (typeof onReady === 'function') onReady(this) 
 
    }); 
 
    } 
 
} 
 

 
new Connection(lovely => { console.log(lovely.connID) })

私はそれが役に立てば幸い!

+0

この約束期間のコールバックは引き続き使用していますか?コンストラクタの外側で 'connId'にアクセスしたい場合はどうなりますか?準備ができているかどうか、彼はどのようにして知りますか? –

+0

@torazaburo私は、何が間違っていたのか、出来事の順序がどのように起こるのかを直接的に示す方法を見ました - 最終的な実装ではありません(したがって、 "...の行に沿ったもの...")。 OPがデータフローを理解した後に約束を使用したい場合は、そうするようにして、回答をガイドとして使用することができます。その代替案を提供していただきありがとうございます。 –

0

一般に、重い初期化ロジックをコンストラクタに置くことは、特に非同期の場合はお勧めできません。見つけたように、コンストラクタは初期化が完了したときの情報を返す方法がありません。別の方法として、接続の準備ができていることを確認することがあります。その後、外のコードで、thenをプロパティから外して、準備ができたらトランンドするコードを指定できます。

class Connection { 
    constructor() { 
    this.connId = new Promise((resolve, reject) => 
     client.incr('conn_id', (err, reply) => { 
     if (err) return reject(err); 
     resolve(reply); 
    }); 
    } 
} 

var lovely = new Connection(); 
lovely.connId . then(connId => console.log(`lovely connID is ${ connID }`); 
関連する問題