2016-05-07 76 views
0

我想要同步獲取mongodb實例。我知道這不是建議,但我只是試驗,並想知道爲什麼這不起作用。 this.db在等待10秒後仍然未定義,通常異步代碼在小於500毫秒內得到它。爲什麼我無法通過同步等待來獲取異步等待的值?

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?