面试题答案
一键面试回调函数基本使用方式
在Node.js中,回调函数是一种以函数作为参数传递给另一个函数的编程模式。通常在异步操作完成时被调用,以处理操作的结果。
例如,使用fs
模块读取文件:
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('读取文件错误:', err);
return;
}
console.log('文件内容:', data);
});
这里fs.readFile
是一个异步函数,它接受文件名、编码和一个回调函数作为参数。当文件读取操作完成后,无论成功或失败,都会调用这个回调函数,并传入相应的参数(错误对象err
或数据data
)。
结合事件循环机制解释多异步I/O操作执行顺序
- 事件循环机制简介:Node.js使用事件驱动、非阻塞I/O模型。事件循环负责不断检查调用栈是否为空,当调用栈为空时,事件循环会从任务队列中取出任务并推到调用栈中执行。
- 多异步I/O操作场景:假设程序中有多个异步I/O操作,如文件读取和网络请求,且都使用回调函数。
const fs = require('fs');
const http = require('http');
// 文件读取操作
fs.readFile('file1.txt', 'utf8', (err, data1) => {
if (err) {
console.error('读取file1.txt错误:', err);
return;
}
console.log('file1.txt内容:', data1);
});
// 网络请求操作
http.get('http://example.com', (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('网络请求结果:', data);
});
}).on('error', (err) => {
console.error('网络请求错误:', err);
});
console.log('主程序继续执行');
- 执行顺序:
- 首先,主程序开始执行,同步代码依次执行。
fs.readFile
和http.get
都是异步操作,它们会将自身的回调函数注册到相应的I/O观察者(文件系统观察者或网络观察者)中,然后立即返回,不会阻塞主程序的执行。 - 接着,
console.log('主程序继续执行');
被执行,打印出相应信息。 - 当文件读取操作完成后,文件系统观察者将文件读取的回调函数放入任务队列。同样,当网络请求完成后,网络观察者将网络请求的回调函数放入任务队列。
- 事件循环不断检查调用栈,当调用栈为空时,事件循环从任务队列中取出任务(回调函数),按照先进先出的顺序将其推到调用栈中执行。所以,如果文件读取操作先完成,那么文件读取的回调函数会先被执行,打印出文件内容;如果网络请求先完成,那么网络请求的回调函数会先被执行,打印出网络请求结果。
- 首先,主程序开始执行,同步代码依次执行。
总结来说,异步I/O操作的回调函数在操作完成后进入任务队列,由事件循环按照顺序将其放入调用栈执行,而主程序会在注册完异步操作后继续执行同步代码,不会等待异步操作完成。