I'm writing a global error handling "module" for one of my applications.
One of the features I want to have is to be able to easily wrap a function with a try{} catch{}
block, so that all calls to that function will automatically have the error handling code that'll call my global logging method. (To avoid polluting the code everywhere with try/catch blocks).
This is, however, slightly beyond my understanding of the low-level functioning of JavaScript, the .call
and .apply
methods, and the this
keyword.
I wrote this code, based on Prototype's Function.wrap
method:
Object.extend(Function.prototype, { TryCatchWrap: function() { var __method = this; return function() { try { __method.apply(this, arguments) } catch(ex) { ErrorHandler.Exception(ex); } } } });
Which is used like this:
function DoSomething(a, b, c, d) { document.write(a + b + c) alert(1/e); } var fn2 = DoSomething.TryCatchWrap(); fn2(1, 2, 3, 4);
That code works perfectly. It prints out 6, and then calls my global error handler.
My question is: will this break something when the function I'm wrapping is within an object, and it uses the "this" operator? I'm slightly worried since I'm calling .apply, passing something there, I'm afraid this may break something.
The wrap() method wraps specified HTML element(s) around each selected element.
A wrapper function is a subroutine (another word for a function) in a software library or a computer program whose main purpose is to call a second subroutine or a system call with little or no additional computation.
jQuery wrap() method is used to wrap specified HTML elements around each selected element. The wrap () function can accept any string or object that could be passed through the $() factory function. Syntax: $(selector).
Personally instead of polluting builtin objects I would go with a decorator technique:
var makeSafe = function(fn){ return function(){ try{ return fn.apply(this, arguments); }catch(ex){ ErrorHandler.Exception(ex); } }; };
You can use it like that:
function fnOriginal(a){ console.log(1/a); }; var fn2 = makeSafe(fnOriginal); fn2(1); fn2(0); fn2("abracadabra!"); var obj = { method1: function(x){ /* do something */ }, method2: function(x){ /* do something */ } }; obj.safeMethod1 = makeSafe(obj.method1); obj.method1(42); // the original method obj.safeMethod1(42); // the "safe" method // let's override a method completely obj.method2 = makeSafe(obj.method2);
But if you do feel like modifying prototypes, you can write it like that:
Function.prototype.TryCatchWrap = function(){ var fn = this; // because we call it on the function itself // let's copy the rest from makeSafe() return function(){ try{ return fn.apply(this, arguments); }catch(ex){ ErrorHandler.Exception(ex); } }; };
Obvious improvement will be to parameterize makeSafe() so you can specify what function to call in the catch block.
2017 answer: just use ES6. Given the following demo function:
function doThing(){ console.log(...arguments) }
You can make your own wrapper function without needing external libraries:
function wrap(someFunction){ function wrappedFunction(){ var newArguments = [...arguments] newArguments.push('SECRET EXTRA ARG ADDED BY WRAPPER!') console.log(`You're about to run a function with these arguments: \n ${newArguments}`) return someFunction(...newArguments) } return wrappedFunction }
In use:
doThing('one', 'two', 'three')
Works as normal.
But using the new wrapped function:
const wrappedDoThing = wrap(doThing) wrappedDoThing('one', 'two', 'three')
Returns:
one two three SECRET EXTRA ARG ADDED BY WRAPPER!
2016 answer: use the wrap
module:
In the example below I'm wrapping process.exit()
, but this works happily with any other function (including browser JS too).
var wrap = require('lodash.wrap'); var log = console.log.bind(console) var RESTART_FLUSH_DELAY = 3 * 1000 process.exit = wrap(process.exit, function(originalFunction) { log('Waiting', RESTART_FLUSH_DELAY, 'for buffers to flush before restarting') setTimeout(originalFunction, RESTART_FLUSH_DELAY) }); process.exit(1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With