[英]node-mysql timing
我有这样的递归查询(注意:这只是一个例子):
var user = function(data)
{
this.minions = [];
this.loadMinions = function()
{
_user = this;
database.query('select * from users where owner='+data.id,function(err,result,fields)
{
for(var m in result)
{
_user.minions[result[m].id] = new user(result[m]);
_user.minions[result[m].id].loadMinions();
}
}
console.log("loaded all minions");
}
}
currentUser = new user(ID);
for (var m in currentUser.minions)
{
console.log("minion found!");
}
这不起作用,因为timmings都是错误的,代码不等待查询。
我试过这样做:
var MyQuery = function(QueryString){
var Data;
var Done = false;
database.query(QueryString, function(err, result, fields) {
Data = result;
Done = true;
});
while(Done != true){};
return Data;
}
var user = function(data)
{
this.minions = [];
this.loadMinions = function()
{
_user = this;
result= MyQuery('select * from users where owner='+data.id);
for(var m in result)
{
_user.minions[result[m].id] = new user(result[m]);
_user.minions[result[m].id].loadMinions();
}
console.log("loaded all minions");
}
}
currentUser = new user(ID);
for (var m in currentUser.minions)
{
console.log("minion found!");
}
但他暂时冻结,我错过了什么?
每个Node.js进程都是单线程的,所以这一行
while(Done != true){};
接管线程,并且将Done
设置为true的回调永远不会运行,因为thead在无限循环上被阻塞。
您需要重构您的程序,以便依赖于查询结果的代码包含在回调本身中。 例如,使MyQuery
采用回调参数:
MyQuery = function(QueryString, callback){
然后在database.query
回调结束时调用回调 - 或者甚至将其作为 database.query
回调提供。
解决问题的第一个障碍是理解Node.js中的I / O是异步的。 一旦你知道这是如何适用于你的问题,递归部分将更容易(特别是如果你使用流控制库,如Async或Step)。
下面是一个示例,它会执行您尝试执行的操作(减去递归)。 就个人而言,我会避免递归加载可能未知数量/深度的记录; 而是按需加载它们,如下例所示:
var User = function(data) {
this.data = data
this.minions;
};
User.prototype.getMinions = function(primaryCallback) {
var that = this; // scope handle
if(this.minions) { // bypass the db query if results cached
return primaryCallback(null, this.minions);
}
// Callback invoked by database.query when it has the records
var aCallback = function(error, results, fields) {
if(error) {
return primaryCallback(error);
}
// This is where you would put your recursive minion initialization
// The problem you are going to have is callback counting, using a library
// like async or step would make this party much much easier
that.minions = results; // bypass the db query after this
primaryCallback(null, results);
}
database.query('SELECT * FROM users WHERE owner = ' + data.id, aCallback);
};
var user = new User(someData);
user.getMinions(function(error, minions) {
if(error) {
throw error;
}
// Inside the function invoked by primaryCallback(...)
minions.forEach(function(minion) {
console.log('found this minion:', minion);
});
});
在这个例子中最值得注意的是回调。 database.query(...)
是异步的,你不想绑定等待它完成的事件循环。 这是通过向查询提供回调aCallback
来解决的,该回调在结果准备好时执行。 一旦该回调触发,并且在对记录执行任何处理之后,您可以使用最终结果触发primaryCallback
。
不幸的是,冻结是正确的行为,因为Node是单线程的。
您需要一个调度程序包来解决此问题。 就个人而言,我一直在使用Fibers-promise来解决这类问题。 您可能希望查看此或其他promise库或异步
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.