NodeJS开发人员常见五个错误理解
1. Node.js 是单线程的,一定不会出现并行执行的情况
这是一个非常常见的错误理解,实际上 Node.js 并不是单线程的,它的事件循环机制可以充分利用多核 CPU 资源来并行执行代码。但是由于 Node.js 中的 I/O 操作都是异步非阻塞的,因此如果不加注意,在异步操作没有完成之前,事件循环会直接进入下一步操作,这会导致异步操作的结果无法预测,从而造成一些错误。
示例1:
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
预期输出为:0 1 2 3 4
实际输出为:5 5 5 5 5
因为在事件循环的过程中,for 循环执行完毕后,i 已经变成了 5,而在 1 秒后打印 i 的值,因此输出了 5 个 5。
示例2:
const fs = require('fs')
fs.readFile('./file1.txt', (err, data1) => {
if (err) throw err
console.log(data1.toString())
})
fs.readFile('./file2.txt', (err, data2) => {
if (err) throw err
console.log(data2.toString())
})
由于 fs.readFile 是异步的,并且是非阻塞的,因此在读取 file1.txt 和 file2.txt 的过程中,是同时进行的,但它们的完成顺序是无法预测的。因此,输出结果也是无法预测的。
2. 回调函数中的异步操作会按照定义的顺序执行
这是另一个常见的错误理解,实际上,在回调函数中定义的异步操作,是不会按照定义的顺序执行的。相反,由于 JavaScript 的异步机制,它们可能会在任何时候完成,这取决于它们的执行时间和当前事件循环的状态。
示例:
function fetchData(id, cb) {
setTimeout(() => {
console.log(`fetch data ${id} completed`)
cb()
}, Math.random() * 1000)
}
function fetchDataList() {
[1, 2, 3, 4, 5].forEach((id) => {
fetchData(id, () => {
console.log(`handle data ${id}`)
})
})
}
fetchDataList()
由于每次调用 fetchData 时,都是使用了随机生成的延迟执行时间,因此输出的顺序是无法确定的。可能的输出结果如下:
fetch data 1 completed
fetch data 3 completed
handle data 1
fetch data 5 completed
handle data 3
fetch data 2 completed
handle data 5
fetch data 4 completed
handle data 2
handle data 4
3. Node.js 不需要异常处理,可以直接用 throw 抛出异常
这是一个非常危险的错误理解,实际上 Node.js 中的异常必须处理,否则可能导致程序崩溃或者数据丢失。如果在回调函数中使用 throw 抛出异常,会直接导致程序崩溃,如果在错误处理中没有处理好异常,也会导致程序崩溃。
示例:
const fs = require('fs')
fs.readFile('./file.txt', (err, data) => {
if (err) throw err // 这里抛出异常会导致程序崩溃
console.log(data.toString())
})
正确的异常处理方式应该是在错误处理中使用 console.error 输出错误信息,并使用 return 或者调用回调函数传递错误信息。示例:
const fs = require('fs')
fs.readFile('./file.txt', (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data.toString())
})
4. 不需要手工关闭文件和数据库连接,Node.js 会自动关闭它们
这是一个常见的错误理解,并不是所有的 Node.js 模块都会自动关闭它们打开的文件和数据库连接,因此必须手工关闭它们。如果没有手工关闭它们,会导致文件描述符泄漏、数据库连接数增加等问题,从而导致程序崩溃或者资源耗尽。
示例:
const fs = require('fs')
const readStream = fs.createReadStream('./file.txt')
readStream.pipe(process.stdout)
// 必须手工关闭 readStream
readStream.on('close', () => {
console.log('readStream closed')
})
5. 使用 console.log 输出日志就足够了
这也是一个常见的错误理解,实际上使用 console.log 可以输出简单的文本日志信息,但是在复杂的项目中,往往需要更加强大、灵活的日志功能。因此,建议使用专业的日志框架,例如 bunyan、winston 等,它们可以帮助开发人员实现一些高级日志功能,例如日志滚动、日志分级、日志归档等。
示例:
const bunyan = require('bunyan');
const logger = bunyan.createLogger({name: 'myapp'});
logger.info('hello world');
上面的代码使用了 bunyan 日志框架,输出了一个简单的日志信息。bunyan 支持非常灵活的日志配置和输出,可以满足各种复杂的项目需求。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:NodeJS开发人员常见五个错误理解 - Python技术站