function first(...args) {
console.log("first :: does succeed :: argsList :", args);
return args.join(', ');
}
function second(...args) {
console.log("second :: going to fail :: argsList :", args);
throw new Error('2nd invocation failed.');
}
function third(...args) {
console.log("third :: going to fail :: argsList :", args);
throw new Error('3rd invocation failed.');
}
function fourth(...args) {
console.log("fourth :: does succeed :: argsList :", args);
return args.join(', ');
}
function fifth(...args) {
console.log("fifth :: does succeed :: argsList :", args);
return args.join(', ');
}
/**
* reduce functionality which processes an array of functions.
*/
function collectResultAfterThrowing(collector, fct, idx) {
function afterThrowingHandler(error, argsArray) {
// - can access the try-catch exception and the arguments
// that have been passed prior to the invocation failure.
return {
success: false,
failure: {
message: error.toString(),
argsList: Array.from(argsArray)
}
}
}
function unifyResult(value) {
return ((
value
&& value.hasOwnProperty('success')
&& (value.success === false)
&& value
) || { success: true, value });
}
collector.results.push(
unifyResult(fct // - modify original function towards an
.afterThrowing(afterThrowingHandler) // `afterThrowing` handling of its try-catch result(s).
.apply(null, collector.listOfArguments[idx])
)
// - an `afterThrowing` modified function does always return either the result of the
// original function's invocation or the return value of its 'afterThrowing' handler.
);
return collector;
}
/**
* reduce functionality which processes an array of functions.
*/
function collectResultAfterFinally(collector, fct, idx) {
function isError(type) {
return (/^\[object\s+Error\]$/).test(Object.prototype.toString.call(type));
}
function createResult(value) {
return (isError(value) && {
success: false,
message: value.toString()
} || {
success: true,
value
});
}
collector.results.push(
createResult(fct // - modify original function towards an
.afterFinally(() => null) // `afterFinally` handling of its try-catch result(s).
.apply(null, collector.listOfArguments[idx])
)
// - an `afterFinally` modified function does always return either the result of the
// original function's invocation or the try-catch exception of the invocation attempt.
);
return collector;
}
// ... two times, each the actual task,
// ... once based on "afterThrowing" and
// ... once based on "afterFinally" ...
console.log('"afterThrowing" based try-and-catch results :', [
first,
second,
third,
fourth,
fifth
].reduce(collectResultAfterThrowing, {
listOfArguments: [
['foo', 'bar'],
['baz', 'biz'],
['buz', 'foo'],
['bar', 'baz'],
['biz', 'buz']
],
results: []
}).results
);
console.log('\n\n\n');
console.log('"afterFinally" based try-and-catch results :', [
first,
second,
third,
fourth,
fifth
].reduce(collectResultAfterFinally, {
listOfArguments: [
['foo', 'bar'],
['baz', 'biz'],
['buz', 'foo'],
['bar', 'baz'],
['biz', 'buz']
],
results: []
}).results
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function (Function) {
const fctPrototype = Function.prototype;
const FUNCTION_TYPE = (typeof Function);
function isFunction(type) {
return (
(typeof type == FUNCTION_TYPE)
&& (typeof type.call == FUNCTION_TYPE)
&& (typeof type.apply == FUNCTION_TYPE)
);
}
function getSanitizedTarget(target) {
return ((target != null) && target) || null;
}
function afterThrowing/*Modifier*/(handler, target) {
target = getSanitizedTarget(target);
const proceed = this;
return (
isFunction(handler) &&
isFunction(proceed) &&
function () {
const context = target || getSanitizedTarget(this);
const args = arguments;
let result;
try {
result = proceed.apply(context, args);
} catch (exception) {
result = handler.call(context, exception, args);
}
return result;
}
) || proceed;
}
// afterThrowing.toString = () => 'afterThrowing() { [native code] }';
function afterFinally/*Modifier*/(handler, target) {
target = getSanitizedTarget(target);
const proceed = this;
return (
isFunction(handler) &&
isFunction(proceed) &&
function () {
const context = target || getSanitizedTarget(this);
const args = arguments;
let result, error;
try {
result = proceed.apply(context, args);
} catch (exception) {
error = exception;
} // finally { ... }
result = (error || result);
handler.call(context, result, args);
return result;
}
) || proceed;
}
// afterFinally.toString = () => 'afterFinally() { [native code] }';
Object.defineProperty(fctPrototype, 'afterThrowing', {
configurable: true,
writable: true,
value: afterThrowing/*Modifier*/
});
Object.defineProperty(fctPrototype, 'afterFinally', {
configurable: true,
writable: true,
value: afterFinally/*Modifier*/
});
}(Function));
</script>