【问题标题】:Nodejs/Javascript hoisting, variable remains undefindNodejs/Javascript 提升,变量未定义
【发布时间】:2016-07-31 20:44:00
【问题描述】:
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 数组获取值但仍处于 undefind 状态,exp 数组获取值且不会重新进行 undefind。我可以请你帮我解决这个问题。

【问题讨论】:

  • 这与吊装无关。甚至没有范围。 (或者,好吧,也许是tiny little bit
  • @Bergi - 该副本实际上并没有建议 OP 如何解决他们的具体问题,因为他们需要知道 N 个回调何时完成。是的,它涵盖了一般主题,但没有针对这个问题提供具体的解决方案。
  • @Bergi - 而且,这段代码还有一个for 循环索引问题,在 dup 中也没有描述。

标签: javascript html node.js pug hoisting


【解决方案1】:

这里至少存在三个问题:

  1. 异步回调的计时问题。
  2. 您的 for 循环索引在异步回调中无效。
  3. 您的错误处理不起作用,因为在异步回调内部执行 throw 并没有任何用处。

这里有关于每个问题的更多详细信息。

您的主要问题是这是一个时间问题。 connection.query() 是异步的。这意味着它不会阻塞,它会在未来一段时间内完成。因此,您调用connection.query() 并且其他代码继续运行。事实上,您的整个 for 循环会从所有 connection.query() 调用开始运行,然后一段时间后,会为每个 connection.query() 调用回调。

因此,如果您在 response.render() 调用中查找 usN 的值,它还没有值,因为尚未完成任何 connection.query() 操作,因此尚未调用回调。您可以可靠地使用 usN 值的唯一地方是在您的 connection.query() 回调中。由于您在 for 循环中多次执行此操作,因此您必须跟踪所有回调何时完成。

有许多不同的方法可以解决这个问题,但这里有一种方法,您可以记录 for 循环中有多少异步回调已完成,并在它们全部被调用时调用渲染。

另外,由于回调被稍后调用,你的for循环索引i在回调中也不再有效。这可以通过将其全部包装在一个 IIFE 中来解决,该 IIFE 为每个回调分别捕获循环计数器。

而且,尝试在回调中使用if(err2) throw err2; 不会做任何有用的事情,因为在这种类型的异步回调中执行throw 只会抛出数据库代码,并且不会是您可以在自己的代码中的任何地方捕获的东西。相反,您将不得不通过某种您自己的回调来反馈错误。 Promise 实际上是一种更好的交流和传播异步错误的方式。这是一个修复了前两项的实现(此处未更正错误处理,因为这需要一些其他结构更改):

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);             
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-20
    • 2015-06-22
    • 1970-01-01
    • 2018-06-29
    • 2017-08-03
    • 1970-01-01
    • 2023-03-14
    • 2018-05-29
    相关资源
    最近更新 更多