Nodejs/Javascript 提升,变量保持未定义
Nodejs/Javascript hoisting, variable remains undefind
var exp = [];
connection.query(`select *
from glossary
where ${connection.escape(word)} = word`,
function(err, rows, fields){
if(err) throw err;
if(rows.length > 0){
for (var i = 0; i < rows.length; i++) {
exp[i] = "Explanation: " + rows[i].explanation + ' ';
}
var usN = [];
for (var i = 0; i < rows.length; i++) {
connection.query("select * from users where id =" + rows[i].userID, function(err2, rows2, fields2){
if(err2) throw err2;
if(rows2.length > 0){
usN[i] = "Edited by: " + rows2[0].username;
}
});
}
response.render("gloss.jade", { user: request.session.user, logedIn: request.session.user, yourWord: word, exp: exp, users: usN});
}
}
)
usN数组取值未定义,exp数组取值未未定义。我可以请你帮我解决这个问题吗?
这里至少存在三个问题:
- 异步回调的计时问题。
- 您的
for
循环索引在异步回调中无效。
- 您的错误处理不会起作用,因为从异步回调内部执行
throw
不会做任何有用的事情。
这里有关于每个问题的更多详细信息。
你的主要问题是这是一个时间问题。 connection.query()
是异步的。这意味着它不会阻塞并且会在未来某个时间完成。因此,您调用 connection.query()
,其他代码继续到 运行。事实上,您的整个 for
循环 运行 开始所有 connection.query()
调用,然后,一段时间后,为每个 connection.query()
.
调用回调
因此,如果您在 response.render()
调用中查找 usN
的值,它还没有值,因为 connection.query()
操作中的 none尚未完成,因此尚未调用回调。唯一可以可靠地使用 usN
值的地方是在 connection.query()
回调中。由于您在 for
循环中多次执行此操作,因此您必须跟踪所有回调何时完成。
有许多不同的方法可以解决这个问题,但这里有一个方法,您可以在其中记录 for
循环中有多少异步回调已完成,并在它们全部被调用时调用渲染.
此外,由于稍后调用回调,您的 for
循环索引 i
在回调内也不再有效。这可以通过将其全部包装在一个 IIFE 中来解决,该 IIFE 为每个回调分别捕获循环计数器。
而且,在回调中尝试 if(err2) throw err2;
不会做任何有用的事情,因为在这种类型的异步回调中做 throw
只会抛出数据库代码,而不是你可以捕捉到的东西在您自己的代码中的任何位置。相反,您将不得不通过某种您自己的回调来传达错误。 Promises 实际上是一种更好的交流和传播异步错误的方式。这是修复了前两项的实现(此处未更正错误处理,因为这需要进行一些其他结构更改):
function(err, rows, fields){
if(err) throw err;
if(rows.length > 0){
for (var i = 0; i < rows.length; i++) {
exp[i] = "Explanation: " + rows[i].explanation + ' ';
}
var usN = [];
var cnt = 0;
for (var i = 0; i < rows.length; i++) {
(function(index) {
connection.query("select * from users where id =" + rows[i].userID, function(err2, rows2, fields2){
// ISSUE: doing a throw here does nothing useful
// as it just goes back into the async database code
// You need a better way to propagate errors
if(err2) throw err2;
if(rows2.length > 0){
usN[index] = "Edited by: " + rows2[0].username;
}
// see if this is the last callback
++cnt;
if (cnt === rows.length) {
response.render("gloss.jade", { user: request.session.user, logedIn: request.session.user, yourWord: word, exp: exp, users: usN});
}
});
})(i);
}
}
}
var exp = [];
connection.query(`select *
from glossary
where ${connection.escape(word)} = word`,
function(err, rows, fields){
if(err) throw err;
if(rows.length > 0){
for (var i = 0; i < rows.length; i++) {
exp[i] = "Explanation: " + rows[i].explanation + ' ';
}
var usN = [];
for (var i = 0; i < rows.length; i++) {
connection.query("select * from users where id =" + rows[i].userID, function(err2, rows2, fields2){
if(err2) throw err2;
if(rows2.length > 0){
usN[i] = "Edited by: " + rows2[0].username;
}
});
}
response.render("gloss.jade", { user: request.session.user, logedIn: request.session.user, yourWord: word, exp: exp, users: usN});
}
}
)
usN数组取值未定义,exp数组取值未未定义。我可以请你帮我解决这个问题吗?
这里至少存在三个问题:
- 异步回调的计时问题。
- 您的
for
循环索引在异步回调中无效。 - 您的错误处理不会起作用,因为从异步回调内部执行
throw
不会做任何有用的事情。
这里有关于每个问题的更多详细信息。
你的主要问题是这是一个时间问题。 connection.query()
是异步的。这意味着它不会阻塞并且会在未来某个时间完成。因此,您调用 connection.query()
,其他代码继续到 运行。事实上,您的整个 for
循环 运行 开始所有 connection.query()
调用,然后,一段时间后,为每个 connection.query()
.
因此,如果您在 response.render()
调用中查找 usN
的值,它还没有值,因为 connection.query()
操作中的 none尚未完成,因此尚未调用回调。唯一可以可靠地使用 usN
值的地方是在 connection.query()
回调中。由于您在 for
循环中多次执行此操作,因此您必须跟踪所有回调何时完成。
有许多不同的方法可以解决这个问题,但这里有一个方法,您可以在其中记录 for
循环中有多少异步回调已完成,并在它们全部被调用时调用渲染.
此外,由于稍后调用回调,您的 for
循环索引 i
在回调内也不再有效。这可以通过将其全部包装在一个 IIFE 中来解决,该 IIFE 为每个回调分别捕获循环计数器。
而且,在回调中尝试 if(err2) throw err2;
不会做任何有用的事情,因为在这种类型的异步回调中做 throw
只会抛出数据库代码,而不是你可以捕捉到的东西在您自己的代码中的任何位置。相反,您将不得不通过某种您自己的回调来传达错误。 Promises 实际上是一种更好的交流和传播异步错误的方式。这是修复了前两项的实现(此处未更正错误处理,因为这需要进行一些其他结构更改):
function(err, rows, fields){
if(err) throw err;
if(rows.length > 0){
for (var i = 0; i < rows.length; i++) {
exp[i] = "Explanation: " + rows[i].explanation + ' ';
}
var usN = [];
var cnt = 0;
for (var i = 0; i < rows.length; i++) {
(function(index) {
connection.query("select * from users where id =" + rows[i].userID, function(err2, rows2, fields2){
// ISSUE: doing a throw here does nothing useful
// as it just goes back into the async database code
// You need a better way to propagate errors
if(err2) throw err2;
if(rows2.length > 0){
usN[index] = "Edited by: " + rows2[0].username;
}
// see if this is the last callback
++cnt;
if (cnt === rows.length) {
response.render("gloss.jade", { user: request.session.user, logedIn: request.session.user, yourWord: word, exp: exp, users: usN});
}
});
})(i);
}
}
}