2016-05-07 26 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?