Node.js回调函数的简单示例

140

有没有人能给我一个简单的Node.js回调函数的例子?我已经在许多网站上搜索了,但是仍然不能很好地理解它,请给我一个简单的例子。

getDbFiles(store, function(files){
    getCdnFiles(store, function(files){
    })
})

我想做类似那样的事情...


如何编写一个接受回调函数作为参数的函数的示例? - Gntem
是的,就像那样,有没有简单的例子可以帮助我理解它。 - Bhushan Goel
3
回调函数是作为参数传递给另一个函数的函数。请在谷歌中搜索“callback javascript”,点击第一个结果以获取更多信息。 - Gabriel Llamas
10个回答

219
var myCallback = function(data) {
  console.log('got data: '+data);
};

var usingItNow = function(callback) {
  callback('get it?');
};

现在打开节点或浏览器控制台,然后粘贴上面的定义。

最后使用下一行代码:

usingItNow(myCallback);

关于节点风格的错误惯例

Costa问如果我们遵守节点错误回调惯例,那么这会是什么样子。

按照这个惯例,回调函数应该至少接收一个参数,即第一个参数作为错误。根据上下文情况,我们可能还会有一个或多个其他的可选参数。在这种情况下,上述示例就是我们的上下文。

下面我将按照这个惯例重新编写我们的示例。

var myCallback = function(err, data) {
  if (err) throw err; // Check for the error and throw if it exists.
  console.log('got data: '+data); // Otherwise proceed as usual.
};

var usingItNow = function(callback) {
  callback(null, 'get it?'); // I dont want to throw an error, so I pass null for the error argument
};
如果我们想模拟错误情况,我们可以这样定义 usingItNow。
var usingItNow = function(callback) {
  var myError = new Error('My custom error!');
  callback(myError, 'get it?'); // I send my error as the first argument.
};

最终的用法与上面完全相同:

usingItNow(myCallback);

只有一个行为上的区别,取决于你定义的usingItNow版本:是将“真值”(错误对象)提供给回调函数作为第一个参数的版本,还是将 null 作为错误参数提供给它。


那么如果将错误作为第一个参数约定,这会是什么样子呢? - Costa Michailidis

123

回调函数就是你将一个函数传递给另一个函数,以便该函数可以在稍后的时间调用它。这在异步API中很常见;API调用立即返回,因为它是异步的,所以你要将一个函数传递给它,当API完成其异步任务时,它可以调用该函数。

我能想到的JavaScript中最简单的例子是setTimeout()函数。它是一个全局函数,接受两个参数。第一个参数是回调函数,第二个参数是延迟的毫秒数。该函数被设计成等待适当的时间,然后调用你的回调函数。

setTimeout(function () {
  console.log("10 seconds later...");
}, 10000);

你可能之前见过上面的代码,但没有意识到你传递的函数被称为回调函数。我们可以重写上面的代码,使其更加明显。
var callback = function () {
  console.log("10 seconds later...");
};
setTimeout(callback, 10000);

回调函数在Node中随处可见,因为Node从头开始构建为异步执行。即使是在与文件系统交互时也是如此。这就是为什么许多内部Node API接受回调函数作为参数而不是返回数据以便你可以将其分配给变量。它将调用您的回调函数,并将您想要的数据作为参数传递。例如,您可以使用Node的fs库读取文件。 fs模块公开了两个独特的API函数:readFilereadFileSync

readFile函数是异步的,而readFileSync显然不是。您可以看到他们希望您尽可能使用异步调用,因为他们称它们为readFilereadFileSync而不是readFilereadFileAsync。以下是使用两个函数的示例。

同步:

var data = fs.readFileSync('test.txt');
console.log(data);

上面的代码会阻塞线程执行,直到将test.txt的所有内容读入内存并存储在变量data中。在Node中,通常认为这是一种不良做法。但有时候它是有用的,比如写一个简单但繁琐的脚本,并且您不太关心节省每一纳秒的时间。
异步(带回调函数):
var callback = function (err, data) {
  if (err) return console.error(err);
  console.log(data);
};
fs.readFile('test.txt', callback);

首先,我们创建一个回调函数,接受两个参数errdata。异步函数的一个问题是捕获错误变得更加困难,因此许多基于回调的API将错误作为回调函数的第一个参数传递。最佳实践是在执行任何其他操作之前检查err是否有值。如果有,停止回调的执行并记录错误。
同步调用在抛出异常时具有优势,因为您可以使用try/catch块来捕获它们。
try {
  var data = fs.readFileSync('test.txt');
  console.log(data);
} catch (err) {
  console.error(err);
}

在异步函数中,它不是那样工作的。API调用立即返回,因此没有什么可以使用try/catch来捕获。适当的异步API会始终捕获自己的错误,然后将这些错误传递到回调中,在那里您可以根据需要处理它。
除了回调之外,还有另一种常用的API风格,称为Promise。如果您想阅读有关它们的内容,则可以阅读我基于此答案编写的整个博客文章here

3
对于像我这样的Node.js初学者来说,这是一个相当精细而简洁的概念阐述。 - kmonsoor
3
感谢提供大量的上下文信息。不仅展示了回调函数的外观,还解释了它们是什么、为什么被使用以及为什么会经常使用。对于初学者来说非常有帮助。 - Azurespot
1
太好了!这可以成为一篇独立的文章! - Pablo Glez
1
它是关于回调函数和 Promise 的博客文章,包含第二部分关于 Promise 的内容 ;)。链接地址为 http://codetunnel.io/what-are-callbacks-and-promises。 - Chev
1
这篇解释比被采纳的答案好多了!我希望在 Stack Overflow 上每个被采纳的答案都像这样 - 不仅是解决问题的代码片段,还要包括解决问题的为什么如何。基本上,这个答案和回调地狱会让你对回调有一个相当扎实的理解。 - ruslaniv
显示剩余2条评论

10

这是使用fs.readFilefs.writeFile复制文本文件的示例:

var fs = require('fs');

var copyFile = function(source, destination, next) {
  // we should read source file first
  fs.readFile(source, function(err, data) {
    if (err) return next(err); // error occurred
    // now we can write data to destination file
    fs.writeFile(destination, data, next);
  });
};

这是使用copyFile函数的示例:

copyFile('foo.txt', 'bar.txt', function(err) {
  if (err) {
    // either fs.readFile or fs.writeFile returned an error
    console.log(err.stack || err);
  } else {
    console.log('Success!');
  }
});

常见的Node.js模式建议回调函数的第一个参数为错误对象。您应该使用这个模式,因为所有控制流模块都依赖于它:

next(new Error('I cannot do it!')); // error

next(null, results); // no error occurred, return result

2
下一步是什么?变量results=正在调用什么? - The Nomadic Coder
3
@SemicolonWarrier 给我和其他人的一个指针:https://dev59.com/sW435IYBdhLWcg3wfgIf - kmonsoor

6

尝试这个例子,它非常简单易懂,只需复制保存newfile.js,然后运行该应用程序的命令是node newfile。

function myNew(next){
    console.log("Im the one who initates callback");
    next("nope", "success");
}


myNew(function(err, res){
    console.log("I got back from callback",err, res);
});

4
我们正在创建一个简单的函数,如下所示:
callBackFunction (data, function ( err, response ){
     console.log(response)
}) 

// callbackfunction 
function callBackFuntion (data, callback){
    //write your logic and return your result as
callback("",result) //if not error
callback(error, "") //if error
}

2

//delay callback function
function delay (seconds, callback){
    setTimeout(() =>{
      console.log('The long delay ended');
      callback('Task Complete');
    }, seconds*1000);
}
//Execute delay function
delay(1, res => {  
    console.log(res);  
})


1
// Traditional JS way
function display(result) {
    console.log("Sum of given numbers is", result);
}

function calculateSum(num1, num2, callback) {
    console.log("FIrst number is", num1, "and second number is", num2);
    const result = num1 + num2;
    callback(result);
}

calculateSum(10, 20, display);

// Node JS way
const display = function(result) {
    console.log("Sum of given numbers is", result);
}

const calculateSum = function(num1, num2, callback) {
    console.log("FIrst number is", num1, "and second number is", num2);
    const result = num1 + num2;
    callback(result);
}

calculateSum(10, 20, display);

// By using anonymous function
const calculateSum = function(num1, num2, callback) {
    console.log("FIrst number is", num1, "and second number is", num2);
    const result = num1 + num2;
    callback(result);
}

calculateSum(10,20, function(result) {
    console.log("Sum of given numbers is", result)
}); 

// By using arrow function
const calculateSum = function(num1, num2, callback) {
    console.log("FIrst number is", num1, "and second number is", num2);
    const result = num1 + num2;
    callback(result);
}

calculateSum(10, 20, x => console.log("Sum of given numbers is", x));

1

1
const fs = require('fs');

fs.stat('input.txt', function (err, stats) {
    if(err){
        console.log(err);
    } else {
        console.log(stats);
        console.log('Completed Reading File');
    }
});

'fs'是一个Node.js模块,可以帮助你读取文件。 回调函数将确保在执行之前完全读取名为'input.txt'的文件。 fs.stat()函数用于获取文件信息,如文件大小、创建日期和修改日期。


0

回调函数是作为参数传递给高阶函数wikipedia)的一种函数。一个简单的回调函数实现如下:

const func = callback => callback('Hello World!');

调用该函数,只需将另一个函数作为参数传递给已定义的函数即可。
func(string => console.log(string));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接