2014-02-07 26 views
0

我确实有作用域的变量在Javascript中的问题(的Node.js /快递)的JavaScript Node.js的中作用域

可有人请向我解释为什么是“走出去”变量没有被作用域到最后一行在以下脚本中?

exports.last = function(req, res){ 
    var out = []; 
    var q = Point.find({ token: req.params.token }).distinct('key'); 
    q.exec(function (err, keys, count) { 
    keys.forEach(function(k) { 
     var q2 = Point.findOne({ token: req.params.token, key: k }).sort({time:-1}) 
     q2.exec(function(err, p, count) { 
     out.push({ a: Date.parse(p.time), b: parseFloat(p.val) }); 
     }); 
    }) 
    console.log(out); 
    }) 
    res.json(out); 
}; 
+5

它是“作用域”,但''之前console.log' –

+3

看起来像日常异步HTTP问题是res.json'可能执行://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call – elclanrs

+0

@elclanrs你是对的;我正在投票结束。 –

回答

2

评论是正确的:这不是一个范围界定问题,而是JavaScript异步性质的结果。想象一下,你可以给每一行代码分配一个“步数”。这里是你的代码的简化图(数字是步骤编号,如JavaScript引擎执行的东西,也不行号):

1 var thing = []; 
2 q2.exec(function(){ 
     // some stuff happens 
15  thing.push('hello!'); 
    }); 
3 console.log(thing); // still empty! 

见流如何去1,2,3,跳过函数调用在q2.exec?这是因为q2.exec异步:你说“只要q2.exec完成,调用此函数。”你不知道什么时候会完成。所以它继续进行到第3步,然后执行其他任务......最后,q.exec完成,并执行你的功能(在这个虚构的例子中,它是第15步)。

希望澄清事情。

至于如何修复它,你将不得不使用回调,或更有可能在这种情况下,使用“承诺”。为什么在这种情况下承诺?因为你打了很多次q2.exec,我假设你只想在全部调用完成之后登录到控制台。所以,你可以做这样的事情(使用Q承诺库):

var Q = require('q'); // this has nothing to do with your 'q2' 
var promises = []; 
var thing = []; 
stuff.forEach(function(x,i){ 
    var deferred = Q.defer(); 
    q2.exec(function(){ 
     thing.push('hello ' + i); 
     deferred.resolve(); 
    }); 
    promises.push(deferred.promise); 
}); 
Q.all(promises).then(function(){ 
    // all calls to q2.exec now complete 
    console.log(thing); 
}); 
+1

Promise正在被添加到纯JavaScript中。只是想弄明白。 – TheThirdOne

+0

有一天,是的!它可能很快会在Node中提供,但是如果没有再填充几年,浏览器中将无法使用它,可能是:( –

+0

我刚刚阅读了关于该确切主题的一篇很好的文章,顺便说一句:http: //www.html5rocks.com/en/tutorials/es6/promises/ –