1

这是来自我的 node-webkit 应用程序的 javascript 代码,使用 jquery 和 nedb 来管理数据库。

librodb.find({_id: docs[i].libro}, function (err, bookdoc) {
window.titulo = bookdoc[0].titulo;
window.ISBN = bookdoc[0].ISBN;
});

它从数据库中读取条目并将它们返回到一个数组(bookdoc)中。

for (var i = 0; i < docs.length; i++) {
  librodb.find({_id: docs[i].libro}, function (err, bookdoc) {
  window.titulo = bookdoc[0].titulo;
  window.ISBN = bookdoc[0].ISBN;
  });
  switch(docs[i].razon){
    case 1:
      $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') producidos.</li>');
      break;
      case 2:
        libreriadb.find({_id: docs[i].libreria}, function (err, librarydoc) {
          window.nombre = librarydoc[0].nombre;
        });
        $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') devueltos por Libreria ("'+window.nombre+'"), recibo '+docs[i].documento+'.</li>');
      break;
      case 3:
        $(".listed").append('<li><i class="fa fa-question"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') en stock ingresaron por "'+docs[i].descripcion+'".</li>');
      break;
    }
}

问题是变量 window.titulo 和 window.ISBN 是在读取数据库函数内部定义的,但在外部没有。

如果我使用

window.variablename=

当我在 de librodb.find 函数之后调用变量时,都返回“未定义”。

如果我使用

var 变量名=

或者

变量名=

执行停止并出现以下错误:“ReferenceError:titulo 未定义”(在我尝试从开关调用它的地方)。

在所有这三种情况下,librodb.find 函数中的警报都会返回应该返回的值。

我如何定义或调用变量?

4

2 回答 2

3

您遇到的是 javascript 中异步编程的众多陷阱之一。

以下代码的含义很微妙:

librodb.find({_id: docs[i].libro}, function (err, bookdoc) {
    window.titulo = bookdoc[0].titulo;
    window.ISBN = bookdoc[0].ISBN;
});

librodb.find方法是异步的,这意味着它需要执行后台工作(可能需要等待磁盘访问或网络流量)。它不会停止所有其他代码的运行,而是开始在后台执行操作,一旦完成,它将使用结果调用您的代码。

因此,您所看到的是,当您的代码尝试使用 titulo 和 ISBN 运行时,尚未调用回调,这是您的代码设置window.titulowindow.ISBN尚未运行!

相反,您需要延迟运行代码,直到 find 结果返回。为此,将其移动到回调函数中。当然这意味着一个简单的 for 循环不会做你想要的。相反,您可以使用回调编写自己的异步循环,或者使用诸如async.js之类的库。

如果您自己编写它,它可能类似于以下内容:

var i = 0;

function processNext() {
  librodb.find({_id: docs[i].libro}, function (err, bookdoc) {
    window.titulo = bookdoc[0].titulo;
    window.ISBN = bookdoc[0].ISBN;

    switch(docs[i].razon){
      case 1:
        $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') producidos.</li>');
        next();
      break;
      case 2:
        libreriadb.find({_id: docs[i].libreria}, function (err, librarydoc) {
          window.nombre = librarydoc[0].nombre;

          $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') devueltos por Libreria ("'+window.nombre+'"), recibo '+docs[i].documento+'.</li>');
          next();
        });
      break;
      case 3:
        $(".listed").append('<li><i class="fa fa-question"></i><i class="fa fa-sign-in"></i>El '+docs[i].fecha+' '+docs[i].cantidad+' Libros ("'+window.titulo+'", ISBN: '+window.ISBN+') en stock ingresaron por "'+docs[i].descripcion+'".</li>');
        next();
      break;
    }
  });

  function next() {
    i++;
    if(i < docs.length) {
      processNext();
    }
    else {
      // DONE
    }
}
processNext(); // Start the loop

回调和异步 javascript 肯定需要一些时间来适应。

ps 你真的不应该把值放在窗口上。我没有在您的示例代码中修复它,但现在它在同一个函数中,您应该能够摆脱全局变量并简单地将它们设为普通变量。

于 2014-12-28T01:34:02.780 回答
1

您只需要重新组织代码,以便在回调中利用回调的依赖项。例如:

for (var i = 0; i < docs.length; i++) {
  librodb.find({
    _id: docs[i].libro
  }, function(err, bookdoc) {
    var titulo = bookdoc[0].titulo;
    var ISBN = bookdoc[0].ISBN;
    switch (docs[i].razon) {
      case 1:
        $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El ' + docs[i].fecha + ' ' + docs[i].cantidad + ' Libros ("' + titulo + '", ISBN: ' + ISBN + ') producidos.</li>');
        break;
      case 2:
        libreriadb.find({
          _id: docs[i].libreria
        }, function(err, librarydoc) {
          var nombre = librarydoc[0].nombre;
          $(".listed").append('<li><i class="fa fa-institution"></i><i class="fa fa-sign-in"></i>El ' + docs[i].fecha + ' ' + docs[i].cantidad + ' Libros ("' + titulo + '", ISBN: ' + ISBN + ') devueltos por Libreria ("' + nombre + '"), recibo ' + docs[i].documento + '.</li>');

        });
        break;
      case 3:
        $(".listed").append('<li><i class="fa fa-question"></i><i class="fa fa-sign-in"></i>El ' + docs[i].fecha + ' ' + docs[i].cantidad + ' Libros ("' + titulo + '", ISBN: ' + ISBN + ') en stock ingresaron por "' + docs[i].descripcion + '".</li>');
        break;
    }

  });

}

大局是您的回调函数将根据其结果进行所有处理。

根据经验,你不应该弄乱窗口对象,所以你几乎不想在那里定义任何变量,当然不是像这样的简单情况。

于 2014-12-28T02:07:04.580 回答