If you want to use your existing functions as-is then the two techniques described in tadman's answer are good. However there is a cleaner way to handle this but it needs you to modify your existing functions: just throw an error.
function func1() {if (fail) throw new Error('Failed')}
function func2() {if (fail) throw new Error('Failed')}
function func3() {if (fail) throw new Error('Failed')}
try {
func1(); // This part becomes much cleaner
func2();
func3();
}
catch (e) {
// Error handling is localized to this block of code
console.log(e.message);
}
Ideally for situations like this I personally like to return a custom error so that I know it is caused by my own code and I can handle them properly (mostly just ignore them) and then re-throw other error types. But weather you do this or not is up to you:
class FunctionFailureError extends Error {
constructor(message) {
super(message);
this.code = 'FUNC_FAIL_ERROR';
}
}
function func1() {if (fail) throw new FunctionFailureError('Failed')}
function func2() {if (fail) throw new FunctionFailureError('Failed')}
function func3() {if (fail) throw new FunctionFailureError('Failed')}
try {
func1();
func2();
func3();
}
catch (e) {
if (e.code === 'FUNC_FAIL_ERROR') {
console.log(e.message);
}
else {
throw e;
}
}