2016-05-07 3 views
0

私はmongodbインスタンスを同期的に取得しようとしています。私はこれが推奨されていないことを知っているが、私はちょうど実験し、なぜこれが動作しないのだろうかと思うthis.dbは、通常非同期コードが500ミリ秒未満でそれを取得した場合、10秒後には未定義です。非同期的に待機することで値を取得できないのはなぜですか?

Repository.js:

var mongodb = require('mongodb'); 
var config = require('../config/config'); 

var mongoConfig = config.mongodb; 
var mongoClient = mongodb.MongoClient; 

class Repository { 
    constructor() { 
     (async() => { 
      this.db = await mongoClient.connect(mongoConfig.host); 
     })(); 
    } 

    _getDb(t) { 
     t = t || 500; 
     if(!this.db && t < 10000) { 
      sleep(t); 
      t += 500; 
      this._getDb(t); 
     } else { 
      return this.db; 
     } 
    } 

    collection(collectionName) { 
     return this._getDb().collection(collectionName); 
    } 
} 

function sleep(ms) { 
    console.log('sleeping for ' + ms + ' ms'); 
    var t = new Date().getTime(); 
    while (t + ms >= new Date().getTime()) {} 
} 

module.exports = Repository; 

app.js:

require('../babelize'); 

var Repository = require('../lib/Repository'); 
var collection = new Repository().collection('products'); 
+0

JSはシングルスレッドで、定義により、あなたの忙しいループの存在が設定されることから値を防ぐことができます。 JSが時間を費やしている場合、 'db'を割り当てる機会はありません。この質問を「このコードを書き直すにはどうすればよいのですか」と言い換えればよいでしょう。 – loganfsmyth

+0

私は、問題が少なくとも部分的に問題のタイトルに再提示されるべきだと思います。 「このコード」は、読者が質問の本文を覗くことを要求する。 – jstice4all

+1

一言で言えば、同期関数から非同期の値を返すことはできません。あなたは単にそれをすることはできません。あなたのビジー・ウェイト・ループは、Javascriptが動作する方法では動作しません。イベントループが次のイベントを処理することを許可しないため、データベース完了コールバックは決して呼び出されません。あなたは非同期の結果のためにプログラムしなければなりません。約束を返すか、コールバックを渡す。 – jfriend00

答えて

1

Javascriptのイベントベースのアーキテクチャです。すべてのコードは、イベントキューからイベントによって開始され、次のイベントは、前のイベントのコードが実行を終了したときにのみイベントキューから取得されます。つまり、メインのJavascriptコードはシングルスレッドです。

このように、非同期操作を起動すると操作が開始され、操作が完了するとイベントがイベントキューに入れられます。そのイベント(非同期操作のコールバックを起動する)は、前のイベントのコードが実行を終了してシステムに戻るまで実行されません。

これであなたのコードになりました。非同期操作を起動するコードの実行を開始します。その後、永遠にループし、決してシステムに戻ることはありません。そのため、非同期操作が完了してからのイベントキュー内の次のイベントは、決して実行できません。

したがって、要するに、非同期操作が完了するのを待つループでは回転できません。これは、Javascriptが使用するイベント駆動方式と互換性がありません。非同期補完コールバックを実行するために、イベントシステムに戻ることはありません。だから、デッドロックや無限ループがあるだけです。

代わりに、約束を返したり、後で呼び出されるコールバックを渡したりして、非同期応答をコーディングする必要があります。そして、あなたのコードは実行を終了して、コールバックがいつか将来呼び出されるようにする必要があります。 Javascriptでループを回転させて、何か他のものが走るのを待っている。あなたがここに非同期コーディングオプションを見ることができます

How do I return the response from an asynchronous call?

関連する問題