我遇到了一个非常尴尬的问题。 我创建一个池,连接到数据库,创建连接和查询,获取结果,做一堆东西,然后我必须创建另一个连接和查询,但实际上它必须是动态的,所以我循环我的数组{ {1}}包含数据。
然后会发生更多的代码,我必须创建一个额外的循环,因为我的teacherHours
数组的某些元素必须多次尝试才能从即将到来的查询中获得正确的响应。
接着是另一个循环,它应该循环teacherHours
。现在,这就是它的全部内容。
一堆代码发生在第二个循环中,我准备我的第二个查询,调用connection.query()和回调函数内部我准备我的第三个查询(在做了一些其他的东西之后)这实际上就是Node踢的地方我出去
它给了我availableHours > 0
。我的第三个查询需要访问TypeError: Cannot read property 'tid' of undefined
,因此我尝试像以前一样访问它,但Node不允许它。
我知道查询会返回有用的数据(行),因此它不会成为查询问题,但不会接收数据。实际上我tid
第二个查询的结果,我看到它返回2行,就在它之后,它给了我错误。
对我来说也很奇怪,我的两个循环中的所有console.log都被记录了,第二个查询(包含2行)的console.log在循环运行后被记录,因为查询嵌套不应该返回2行,并且错误出现在循环的第一次迭代中,因为代码应该在该点访问第二个查询。
顺便说一句,我尝试设置一个硬编码而不是console.log("the rowRIDS"+rowRIDS);
只是为了让下一个属性tid
成为错误。我有种感觉,好像变量teacherHours不在范围内,但它应该是一个全局变量。
为了更好地了解我正在谈论的内容,我复制了代码并取消注释了所有的javascript代码,我在其中填充和计算内容。任何帮助都会非常棒,经过近7个小时的尝试和尝试。没有运气的错误。谢谢!
datum
答案 0 :(得分:3)
我认为你来自Python,Java等非异步语言,这就是为什么Node,即JavaScript,似乎为你搞砸了,但实际上它并不是。
您的代码中存在的问题是您在同一query
循环中同时执行所有异步函数,如while
。您需要使用像async
这样的模块,它有助于异步运行和收集结果。
这是更新的代码。
var async = require('async'),
connection;
async.waterfall([
function (cb) {
pool.getConnection(cb);
},
function (conn, cb) {
connection = conn;
connection.query('SELECT * FROM teachers_teaching_tbl WHERE fwdid = 1', cb);
},
function (rows, fields, cb) {
rowArray = rows;
console.log(rowArray);
// HERE HAPPENS
// A LOOOOT OF STUFF
//
// AND teacherHours IS BEING POPULATED
//
// THEN COMES A FOR LOOP
async.eachSeries(teacherHours, function (teacherHour, done) {
// MORE STUFF
//
//AND ANOTHER LOOP
async.whilst(function () {
return availableHours > 0;
}, function (cb) {
// AGAIN A BUNCH OF STUFF
//
// NOW I'M PREPARING MY NEXT QUERY
//
var myQueryGetFreeRoom =
"SELECT rms.rid FROM rooms_tbl AS rms WHERE NOT EXISTS ("
+ "SELECT NULL FROM classes_tbl AS cls"
+ " WHERE ("
+ "(cls.bis > '" + bisMinus1 + "' AND cls.bis <= '" + realBis + "')"
+ " OR (cls.von > '" + bisMinus1 + "' AND cls.von < '" + realBis + "')"
+ ") AND ("
+ "cls.datum = '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "'"
+ ") AND cls.rid = rms.rid";
async.waterfall([
function (cb) {
connection.query(myQueryGetFreeRoom, cb);
},
function(rowRIDS, fields, cb) {
roomIDs = rowRIDS;
console.log("the rowRIDS" + rowRIDS);
//
// MORE STUFF
// HAPPENING
//
if (roomIDs.length > 0) {
//
// PREPARING QUERY NO.3 - WHICH IS WHERE MY ERROR POINTS - TO THE USE OF tid PROPERTY
//
var myQueryBookClass = "INSERT INTO classes_tbl (rid, tid, belegtAnz, datum, von, bis) VALUES ("
+ Math.floor(Math.random() * roomIDs.length)
+ ", " + teacherHour.tid
+ ", 0, '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "', '" + bisMinus1 + "', '" + realBis + "')";
console.log("myQueryBookClass: " + myQueryBookClass);
availableHours = 0;
//
// HERE WAS SUPPOSED TO FOLLOW QUERY 3 - myQueryBookClass
//
// BUT SINCE I DONT EVEN GET INSIDE HERE IT IS IN COMMENTS
//
connection.query(myQueryBookClass, function (err, insertRows, fields) {
if (err) {
console.error('error querying: '+err.stack);
return;
}
console.log("Inserted Rows: "+ insertRows);
// Here do whatever you need to do, then call the callback;
cb();
});
} else {
--availableHours;
//
// STUFF HAPPENING
//
cb();
}
}
], function (err) {
if (!err) {
// Notice that you are decrementing the `availableHours` twice here and above.
// Make sure this is what you want.
--availableHours;
}
cb(err);
});
}, done);
}, function (err) {
connection.release(function (err) {
if (err) {
console.error('error disconnecting: ' + err.stack);
return;
}
});
});
}
], function (err) {
conn && pool.release(conn);
err && throw err;
});
下次请正确格式化您的代码以获得更好的可读性,这有助于您更快地获得答案,并将问题文本拆分为段落用于相同目的。
<强>解释强>
有四个嵌套async
流程:
async.waterfall
-> async.eachSeries
-> async.whilst
-> async.waterfall
基本上,async.waterfall
库允许您执行系列函数列表。
cb
(您可以随意调用它,例如。callback
) 。规则是调用它,否则,下一个函数永远不会被执行,因为前一个函数似乎没有完成它的工作。上一个功能完成后,会使用以下签名调用提供的cb
:
cb(err, connection);
如果请求连接时出错,整个async.waterfall
将中断,最终回调函数将被执行。
async
模块将前一个函数的所有参数作为第一个,第二个等参数传递给下一个函数,这就是第二个函数接收conn
作为第一个参数的原因。每个下一个函数都会收到回调cb
作为最后一个参数,当作业完成时你最终必须调用它。
因此,在第一个async.waterfall
流程中:
async.eachSeries
允许按顺序遍历给定值数组。
在第二个async.eachSeries
流程中:
teacherHours
数组中的每个元素。done
回调。同样,您可以将其称为cb
,就像之前的async.waterfall
或callback
一样。 done
只是为了清楚说明该过程已完成。然后我们有async.whilst
提供与普通while () {}
语句相同的逻辑,但是异步处理循环。
在第三个async.whilst
流程中:
availableHours > 0
),则调用第二个函数。cb
以指示它已结束。然后async
模块将调用第一个函数来检查它是否必须继续循环。在async.whilst
内的这个异步函数中,我们有另一个async.waterfall
,因为您需要为每个teacherHour
发送查询到数据库。
在最后的第四个async.watercall
流程中:
SELECT
查询发送到数据库。rowRIDS
可用后,它会调用waterfall
。rowRIDS
(roomIDs.length > 0
),则会将INSERT
查询发送到数据库。cb
。rowRIDs
,它也会调用回调cb
来表明作业已完成。JavaScript是异步的,这是一件好事。当你从其他同步语言转换时,开头可能很难,但是一旦你明白了,就很难同步。它变得非常直观,你会开始思考为什么其他语言不能异步工作。
我希望我能彻底解释上述代码。享受JavaScript!真棒!