我只是从node.js开始。我做了一些ajax的工作,但是没有什么太复杂的,所以回调仍然有点麻烦。我看了看异步,但我所需要的只是顺序运行一些功能。
我基本上有一些东西可以从API中提取一些JSON,然后创建一个新的JSON,然后对此进行处理。显然,我不能只运行它,因为它可以一次运行所有内容并且具有空的JSON。通常,流程必须按顺序运行,但是如果在从API中提取JSON时可以在等待时提取其他JSON,那很好。将回调置于循环中时,我只是感到困惑。我该如何处理索引?我想我已经看到一些地方在循环中使用回调作为递归函数,而根本不使用循环。
简单的例子会很有帮助。
如果在与循环定义相同的作用域中定义了回调(通常是这种情况),则回调将有权访问index变量。暂时搁置NodeJS的细节,让我们考虑一下这个函数:
function doSomething(callback) {
callback();
}
该函数接受回调函数引用,而它所做的就是调用它。不太令人兴奋。:-)
现在让我们在循环中使用它:
var index;
for (index = 0; index < 3; ++index) {
doSomething(function() {
console.log("index = " + index);
});
}
(在诸如服务器进程之类的计算密集型代码中,最好不要在生产代码中按字面意思进行上述操作,我们稍后再讲。)
现在,当我们运行它时,我们将看到预期的输出:
index = 0
index = 1
index = 2
我们的回调能够访问index
,因为回调是对定义了作用域的数据的 封闭 。(不要担心术语“
closure”,闭包并不复杂。)
我说过最好不要在计算密集型生产代码中执行上述操作,原因是该代码会在 每次迭代 时 都
创建一个函数(除非在编译器中进行了花哨的优化,而V8非常聪明,但通过创建这些函数来进行优化是可以的)不平凡的)。因此,这是一个稍作修改的示例:
var index;
for (index = 0; index < 3; ++index) {
doSomething(doSomethingCallback);
}
function doSomethingCallback() {
console.log("index = " + index);
}
这可能看起来有点令人惊讶,但是它仍然以相同的方式工作,并且仍然具有相同的输出,因为doSomethingCallback
它仍然是over的闭包index
,因此index
在调用时仍能看到as
的值。但是现在只有一个doSomethingCallback
函数,而不是每个循环都有一个新函数。
现在让我们举一个负面的例子,那 是 行不通的:
foo();
function foo() {
var index;
for (index = 0; index < 3; ++index) {
doSomething(myCallback);
}
}
function myCallback() {
console.log("index = " + index); // <== Error
}
之所以失败,是因为myCallback
未在中定义相同的范围(或嵌套范围)中index
进行定义,因此index
在中未定义myCallback
。
最后,让我们考虑在一个循环中设置事件处理程序,因为对此必须要小心。在这里,我们将深入探讨NodeJS:
var spawn = require('child_process').spawn;
var commands = [
{cmd: 'ls', args: ['-lh', '/etc' ]},
{cmd: 'ls', args: ['-lh', '/usr' ]},
{cmd: 'ls', args: ['-lh', '/home']}
];
var index, command, child;
for (index = 0; index < commands.length; ++index) {
command = commands[index];
child = spawn(command.cmd, command.args);
child.on('exit', function() {
console.log("Process index " + index + " exited"); // <== WRONG
});
}
它 看起来
像上面应该工作相同的方式,我们前面的循环一样,但有一个关键的区别。在我们之前的循环中,回调被立即调用,因此它看到了正确的index
值,因为index
还没有机会继续前进。不过,在上面的代码中,我们将在调用回调之前旋转整个循环。结果?我们看
Process index 3 exited
Process index 3 exited
Process index 3 exited
这是关键点。闭包没有其关闭的数据的 副本 ,它具有对其的 实时引用
。因此,当exit
运行这些进程中的每个进程的回调时,循环将已经完成,因此所有三个调用都将看到相同的index
值(其值在循环 结束 时)。
我们可以通过使回调使用不会改变的 其他 变量来解决此问题,如下所示:
var spawn = require('child_process').spawn;
var commands = [
{cmd: 'ls', args: ['-lh', '/etc' ]},
{cmd: 'ls', args: ['-lh', '/usr' ]},
{cmd: 'ls', args: ['-lh', '/home']}
];
var index, command, child;
for (index = 0; index < commands.length; ++index) {
command = commands[index];
child = spawn(command.cmd, command.args);
child.on('exit', makeExitCallback(index));
}
function makeExitCallback(i) {
return function() {
console.log("Process index " + i + " exited");
};
}
现在,我们输出正确的值(以进程退出的顺序):
Process index 1 exited
Process index 2 exited
Process index 0 exited
起作用的方式是,我们分配给exit
事件的回调i
在对的调用中的参数上关闭makeExitCallback
。第一回调makeExitCallback
创建并返回关闭在i
该呼叫到值makeExitCallback
,它在创建关闭第二回调i
为值
该 呼叫makeExitCallback
(这是比不同i
的先前调用值)等。
如果您对上面链接的文章进行了阅读,那么很多事情都应该更加清楚。本文中的术语有些过时(ECMAScript 5使用更新的术语),但是概念没有改变。
问题内容: 我是一个长期的PHP(CodeIgniter和WordPress)开发人员,直到最近才想学习其他几种语言。我已经着手通过node.js学习Ruby(在Rails和Sinatra上),Python(在Flask框架下)和Javascript。 我决定使用每种语言创建一个我能想到的最基本的应用程序,即URL扩展器。除了node.js和Javascript,我已经设法用每种语言创建了一个工作
问题内容: 我需要有关node.js异步特性的帮助。我有一个for循环,该循环从数据库收集数据。“结果”是一个数组,然后应将其返回到主函数。 如何确保循环完成后执行回调? 问题答案: 您可能要考虑使用帮助程序库,例如 异步 https://github.com/caolan/async 它有助于使代码更加一致。 就您而言,您可以查看forEach()方法 调用迭代器时,将使用列表中的项目以及完成时
问题内容: 我在使用redis和nodejs时遇到问题。我必须遍历电话号码列表,并检查我的Redis数据库中是否存在该号码。这是我的代码: “之后”控制台日志出现在“之前”控制台日志之前,并且回调始终返回一个empty 。这是因为如果我很了解,对redis的请求是异步的。但问题是我不知道如何使它起作用。我能怎么做 ? 问题答案: 您有两个主要问题。 您的变量将不是您想要的变量。可以通过更改 数组的
什么是回调? 回调是函数的异步等价物。 在给定任务完成时调用回调函数。 Node大量使用回调。 Node的所有API都以支持回调的方式编写。 例如,读取文件的功能可以开始读取文件并立即将控制返回到执行环境,以便可以执行下一条指令。 一旦文件I/O完成,它将在传递回调函数时调用回调函数,该文件的内容作为参数。 因此没有阻塞或等待文件I/O. 这使得Node.js具有高度可扩展性,因为它可以处理大量请
问题内容: 我是JavaScript和node.js的新手。我想遍历目录并将所有文件统计信息(而不是其他目录)添加到数组中。如下所示,我的代码存在问题,因为回调可能在for循环完成后被调用,因此在回调方法中使用“ i”变量将不起作用。但是代码应如何显示,以便以下代码段起作用?它与闭包有关吗? 感谢帮助! 问题答案: 您需要使用闭包是正确的。您应该将循环的内容包装在一个自调用函数中,以保留每次迭代的
问题内容: 我试图用NodeJS编写代码,从外部API抓取数据,然后使用Mongoose在MongoDB中填充它们。在这之间,我将检查该特定对象是否已经存在于Mongo中。下面是我的代码。 我的问题是,由于NodeJS回调是并行的,因此不会按顺序调用它。我的最终结果将是这样的: 呼叫报告API console.log(长度)= 100 ^^^^^^^^^^^^^^^^^^^^^^^^^ conso