错误优先的回调
Node.js 核心 API 暴露的大多数异步方法都遵循称为错误优先回调的惯用模式。
使用这种模式,回调函数作为参数传给方法。
当操作完成或出现错误时,回调函数将使用 Error
对象(如果有)作为第一个参数传入。
如果没有出现错误,则第一个参数将作为 null
传入。
const fs = require('fs');
function errorFirstCallback(err, data) {
if (err) {
console.error('There was an error', err);
return;
}
console.log(data);
}
fs.readFile('/some/file/that/does-not-exist', errorFirstCallback);
fs.readFile('/some/file/that/does-exist', errorFirstCallback);
JavaScript try…catch
机制不能用于拦截异步 API 产生的错误。
初学者的一个常见错误是尝试在错误优先的回调中使用 throw
:
// 这行不通:
const fs = require('fs');
try {
fs.readFile('/some/file/that/does-not-exist', (err, data) => {
// 错误的假设:在这里抛出...
if (err) {
throw err;
}
});
} catch (err) {
// 这不会捕获抛出的错误!
console.error(err);
}
这不起作用,因为传给 fs.readFile()
的回调函数是异步调用的。
当回调被调用时,周围的代码(包括 try…catch
块)已经退出。
大多数情况下,在回调中抛出错误会使 Node.js 进程崩溃。
如果启用了域,或者已经在 process.on('uncaughtException')
注册了句柄,则可以拦截此类错误。
Most asynchronous methods exposed by the Node.js core API follow an idiomatic
pattern referred to as an error-first callback. With this pattern, a callback
function is passed to the method as an argument. When the operation either
completes or an error is raised, the callback function is called with the
Error
object (if any) passed as the first argument. If no error was raised,
the first argument will be passed as null
.
const fs = require('fs');
function errorFirstCallback(err, data) {
if (err) {
console.error('There was an error', err);
return;
}
console.log(data);
}
fs.readFile('/some/file/that/does-not-exist', errorFirstCallback);
fs.readFile('/some/file/that/does-exist', errorFirstCallback);
The JavaScript try…catch
mechanism cannot be used to intercept errors
generated by asynchronous APIs. A common mistake for beginners is to try to
use throw
inside an error-first callback:
// THIS WILL NOT WORK:
const fs = require('fs');
try {
fs.readFile('/some/file/that/does-not-exist', (err, data) => {
// Mistaken assumption: throwing here...
if (err) {
throw err;
}
});
} catch (err) {
// This will not catch the throw!
console.error(err);
}
This will not work because the callback function passed to fs.readFile()
is
called asynchronously. By the time the callback has been called, the
surrounding code, including the try…catch
block, will have already exited.
Throwing an error inside the callback can crash the Node.js process in most
cases. If domains are enabled, or a handler has been registered with
process.on('uncaughtException')
, such errors can be intercepted.