Reputation: 4278
Depending on the nodejs framework, there are usually two ways to manage errors.
throw new Error('invalid id');
)return { 400: 'invalid id' };
)Due to old advice that throwing errors is inefficient, I always tried to return errors but I prefer throwing errors since they are more convenient. The only article referring to the performance hit was referring to Node v0.
Is it still true?
Update 1
Nvm, I realized I could test it myself. Following code is for reference:
import { performance } from "perf_hooks";
function ThrowException() {
throw new Error("invalid exception");
}
const _ATTEMPT = 1000000;
function ThrowingExceptions() {
const p1 = performance.now();
for (let i = 0; i < _ATTEMPT; i++) {
try {
ThrowException();
} catch (ex: any) {
// log error
}
}
const p2 = performance.now();
console.log(`ThrowingExceptions: ${p2 - p1}`);
}
function ReturnException() {
return { error: { _: "invalid exception" } };
}
function ReturningExceptions() {
const p1 = performance.now();
for (let i = 0; i < _ATTEMPT; i++) {
const ex = ReturnException();
if (ex.error) {
// log error
}
}
const p2 = performance.now();
console.log(`ReturningExceptions: ${p2 - p1}`);
}
function Process() {
ThrowingExceptions();
ReturningExceptions();
ThrowingExceptions();
ReturningExceptions();
}
Process();
Results
ThrowingExceptions: 15961.33209991455
ReturningExceptions: 5.09220027923584
ThrowingExceptions: 16461.43380022049
ReturningExceptions: 3.0963997840881348
Update 2
Creating errors created the largest penalty. Thanks @Bergi
import { performance } from "perf_hooks";
const error = new Error("invalid exception");
function ThrowException() {
throw error;
}
const _ATTEMPT = 1000000;
function ThrowingExceptions() {
const p1 = performance.now();
for (let i = 0; i < _ATTEMPT; i++) {
try {
ThrowException();
} catch (ex: any) {
// log error
}
}
const p2 = performance.now();
console.log(`ThrowingExceptions: ${p2 - p1}`);
}
function ReturnException() {
return { error };
}
function ReturningExceptions() {
const p1 = performance.now();
for (let i = 0; i < _ATTEMPT; i++) {
const ex = ReturnException();
if (ex.error) {
// log error
}
}
const p2 = performance.now();
console.log(`ReturningExceptions: ${p2 - p1}`);
}
function Process() {
ThrowingExceptions();
ReturningExceptions();
ThrowingExceptions();
ReturningExceptions();
}
Process();
Results
ThrowingExceptions: 2897.1585998535156
ReturningExceptions: 3.7821998596191406
ThrowingExceptions: 2905.3162999153137
ReturningExceptions: 4.0701003074646
Upvotes: 7
Views: 2285
Reputation: 916
Your performance measurements have nothing to do with the real situation, the development. You need to think of the performance of the entire software system you develop. And then the picture becomes different.
Effectively, returning the status of the function calls is absolutely inefficient compared with the exception mechanism. Consider this: 1) exceptions happens rarely, because they are designed to handle only exceptional situations (and this is not the same as errors), 2) exceptions propagate automatically due to their technological nature, and, 3) when exceptions are not thrown, they do not incur any performance cost, and if they are thrown, nobody cares of performance, as the throwing, propagation, and catching of exceptions happen only in exceptional situations.
In contrast to exceptions, keeping status in function return
objects incur huge costs, in development, maintenance, and performance. Think about it: if you provide call status information in one function, you have to do the same in the function calling that function, and so on, an entire call chain. Nothing like that happens to exceptions, they just propagate.
In fact, the only performance cost is try
. I faced many questions when people tried to wrap in try
and catch
every function. But that defeats the purpose of exceptions, the same thing goes about many try
in general. The try
block should be placed only in special, strategically chosen places. Propagation of exception should almost never be blocked, excluding rare cases, typically only once per thread, in some special situations — а little more.
Upvotes: 0