How do I exit a function cascade/chain? - javascript

If you create an object with functions that return this, you can create a chain of functions that were called previously and create a cascade of function calls:
var i = {
foo: function () {
// Something here...
return this;
},
bar: function () {
// Something here...
return this;
}
};
i.foo().bar().foo()
But what if an error occurs in bar and I don't want to call foo in that case? How do I break the cascade?
If it is at all possible, I would like to avoid try/catch statements.

Ok, so one straightforward thing is that if you want to handle the case without try/catch you have to put if condition in your functions and obviously you have to return something, so that you can execute further functions on that context instead of exception. So try creating all functionality in a object, and allow execution of your function logic only if someone extends. and on your failure return the base, otherwise return current object. In this was you can avoid creating objects every time.
Example:
Lets Consider You have BaseService where all functionalities are defined, and putting a Layer over it to just extend further, so you can go for this pattern:
foo: function() {
if(<function foo does not belongs to this>) {
.......
.......
if(<on logical failure>) {
return this.__proto__;
}
.......
.......
}
return this;
}
Here is a working snippet:
function BaseService() {
var dataBucket = [13, 50, 45, 57, 95];
this.foo = function() {
if (Object.values(this).indexOf(arguments.callee) === -1) {
console.log('processing foo');
}
return this;
}
this.bar = function() {
if (Object.values(this).indexOf(arguments.callee) === -1) {
console.log('processing bar');
}
return this;
}
this.processValIfExists = function(val) {
if (Object.values(this).indexOf(arguments.callee) === -1) {
console.log('processing processValIfExists');
if (dataBucket.indexOf(val) > -1) {
//process the value further
} else {
return this.__proto__;
}
}
return this;
}
};
//define the extended service, you can add further
//functionalities here. eg: createing the dataBucket here from args
function WrapperService() {};
WrapperService.prototype = new BaseService(); // just extend from any service and use
var svc = new WrapperService();
console.log('----------Executes All-----------');
svc.foo().bar().processValIfExists(95).foo().bar();
console.log('----------Executes upto processValIfExists-----------');
svc.foo().bar().processValIfExists(100).foo().bar();
Note that its just a different approach that came to my mind, and to check for the current invoking method I tried to make the code generic instead of checking if its instance of WrapperService in a BaseService function in order to avoid code coupling and can be extend from any other Service as well.

One could return a new empty instance of i, then on error return an empty obect:
class Chainable {
constructor(data){
this.data = data;
}
foo (foo) {
//if an error occured
if(foo == 10) return new Chainable();
// Something here...
return new Chainable(this.data + foo);
},
bar () {
//if were in an error, fail silently
if(!this.data) return this;
// Something here...
return this;
}
}
(new Chainable(1))
.foo(5).bar().bar().data // 6
(new Chainable(1))
.foo(10).bar().bar().data //undefined

Maybe not what you wanted, but Promises are great for chaining and for error handling:
var i = {
count: 0,
foo: function () {
// Something here...
this.count++;
console.log('foo');
return this.count < 4 ?
Promise.resolve(this) :
Promise.reject(new Error('Count too high!'));
},
bar: function () {
// Something here...
this.count++;
console.log('bar');
return this.count < 4 ?
Promise.resolve(this) :
Promise.reject(new Error('Count too high! Count is ' + this.count));
}
};
i.foo() // first
.then(i => i.bar()) // second
.then(i => i.foo()) // third
.then(i => i.bar()) // too much!
.then(i => i.whatIsThis()) // will not run
.then(i => i.whatIsThis()) // will not run
.catch(error => console.log(error.message));

Related

JS: how to capture output of a function every time it gets called

I have the following self-invoked function which is being utilized by the other functions across the app:
var Api = (function() {
var requestPayload;
var responsePayload;
return {
getRequestPayload: function() {
return requestPayload;
},
setRequestPayload: function(newPayloadStr) {
requestPayload = JSON.parse(newPayloadStr);
},
getResponsePayload: function() { // <-Function's output I need
return responsePayload;
},
setResponsePayload: function(newPayloadStr) {
responsePayload = JSON.parse(newPayloadStr);
}
};
}());
This function is called by other functions in the app like:
Api.getResponsePayload();
I want to capture the output of getResponsePayload function every time this function is called to utilize is for further processing.
I tried to create another function:
function runMe(responsePayload) {
console.log(responsePayload)
}
And it gets called everytime getResponsePayload function is called but the output I'm getting is undefined:
getResponsePayload: function() {
runMe();
return responsePayload;
How can I get the output of getResponsePayload function everytime it gets called by any other function in the app?
Just shim it, assuming this is for debug purposes. You may want to handle exceptions more explicitly, just be sure to rethrow to be transparent.
Api.getResponsePayload = (function(previousFn){
return function() {
var result = previousFn.apply(this, arguments);
// print them or something
return result;
}
})(Api.getResponsePayload)
Edit: Here is a generalisation of the method above:
function logMethodCallsOn(object, methodName) {
var actualMethod = object[methodName];
object[methodName] = function() {
var title = methodName + "(" + Array.prototype.map.call(arguments, function (val) { return JSON.stringify(val); }).join(", ") + ")";
try {
var result = actualMethod.apply(this, arguments);
console.log(title + " =", result);
return result;
} catch (e) {
console.error(title + " threw", e);
throw(e);
}
}
}
logMethodCallsOn(Api, 'getResponsePayload');
logMethodCallsOn(Api, 'setResponsePayload');
You could use callbacks. I'm not sure if you whant a callback in the get or the set, this example shows both.
Eric's answer is more elegant and can be used even if Api is an external object. But I think this simpler implementation could be useful for learning purpose.
var Api = (function(getResponsePayloadCallback, setResponsePayloadCallback) {
var requestPayload;
var responsePayload;
return {
getRequestPayload: function() {
return requestPayload;
},
setRequestPayload: function(newPayloadStr) {
requestPayload = JSON.parse(newPayloadStr);
},
getResponsePayload: function() { // <-Function's output I need
getResponsePayloadCallback(responsePayload);
return responsePayload;
},
setResponsePayload: function(newPayloadStr) {
responsePayload = JSON.parse(newPayloadStr);
setResponsePayloadCallback(responsePayload);
}
};
})(getResponsePayloadHandler, setResponsePayloadHandler);
Api.setResponsePayload('{ "foo": "foo value" }');
var requestPayload = Api.getResponsePayload();
function getResponsePayloadHandler(value) {
console.log("getResponsePayload: " + value.foo);
}
function setResponsePayloadHandler(value) {
console.log("setResponsePayload: " + value.foo);
}
You are not passing any parameter to runMe so it logs undefined. Change your getResponsePayload function to:
getResponsePayload: function() {
runMe(responsePayload);
return responsePayload;
}
Anyway be aware that if you don't set responsePayload, you console output will still be undefined cause responsePayload is only declared but never assigned a value (so it will have undefined value)

How to deal with parameter as a value or an array of values

I have several functions of the form:
this.something = function (which) {
// One or many.
if (!Array.isArray(which)) {
// Normal - just one.
doSomething(which);
} else {
// To all!
which.forEach(function (thing) {
// Note the recursion
something(thing);
});
}
};
Is there a tidier way to do this?
this.something = function(which) {
(Array.isArray(which) ? which : [which]).forEach(function(thing) {
doSomething(thing);
});
};
Not really a fan, but you often see this:
// A function that handles values as a single parameter, or inside an array
var doSomething(x) {
if (Array.isArray(x)) {
x.forEach(doSomething);
} else {
console.log(x);
}
}
Which you could extract from doSomething and apply in a utility method like so:
var ifArrayForEach = f => x => Array.isArray(x) ? x.forEach(f) : f(x);
var doSomething = x => console.log(x);
var doSomethingArrayOrNot = ifArrayForEach(doSomething);
doSomethingArrayOrNot("Hello world");
doSomethingArrayOrNot(["Hello", "world"]);
Again... I'm not a big fan, but sometimes it can be useful. I'd personally just check before calling. At some point you'll have to know what data you're handling anyway...
Not sure if this meets the "Tidier" request you're looking for, but you could always handle it in a try/catch.
try {
which.forEach(function (thing) {
something(thing);
});
} catch (e) {
if (e instanceof TypeError) {
doSomething(which);
}
}

Adding some pre and post logic to a bunch of JavaScript methods

I have a JavaScript object
myObject = function () {
var that = {};
...
that.myMethod1 = myMethod1;
that.myMethod2 = myMethod2;
...
that.myMethodN = myMethodN;
return that;
}
I want to add the exact same pre and post logic to every method. For example a log for entering the method and for exiting the method.
I could with a prePostLogic function such as
function prePostLogic(f2) {
console.log('>> enter');
f2();
console.log('<< exist');
}
and then do:
myObject = {
...
that.myMethod1 = prePostLogic(myMethod1);
that.myMethod2 = prePostLogic(myMethod2);
...
that.myMethodN = prePostLogic(myMethodN);
return that;
}
But what I'd really like is to not have to wrap every method but to write something that would iterate over all methods and wrap them for me. This is so when someone adds a new method they don't have to wrap it.
Please help me?
Thanks
something that would iterate over all methods and wrap them for me
Exactly, just do that:
for (var prop in that)
that[prop] = makePrePostLogic(that[prop]);
function makePrePostLogic(fn) {
return function withLogic() {
console.log(">> enter "+fn.name);
var res = fn.apply(this, arguments);
console.log("<< exit "+fn.name);
return res;
};
}
function prePostLogic(f2) {
return (function(){
console.log('>> enter');
f2();
console.log('<< exit');
});
}
var func = function(){
console.log("Hello World");
}
var method = prePostLogic(func);
method();
In your case
for (var prop in myObject){
if(typeof myObject[prop] == "function"){
myObject[prop] = prePostLogic(myObject[prop]);
}
}

Functional JavaScript: how to implement Function.prototype.not

I was working on some code earlier today, when I realized, "Hey! This code would be more concise and semantic if I abstracted the idea of a boolean not out of an anonymous function and into a prototype function..."
Consider a predicate generator:
function equalTo(n) {
return function(x) {
return n==x;
};
}
So you can use it like so:
[1,2,3,4,1,2,3,4].filter(equalTo(2)) == [2,2]
Now, my idea is to make a predicate "inverser":
Function.prototype.not = function() {
//???
}
So that you can say:
[1,2,3,4,1,2,3,4].filter(equalTo(2).not) == [1,3,4,1,3,4]
My first stab at the implementation was probably very naive:
Function.prototype.not = function () {
return ! this(arguments);
}
And probably why it didn't work.
How would you implement this function, and why?
I'm just trying to wrap my head around functional ideas, and know JavaScript well enough to know it can be used to do this, but just not how.
Your implementation won't work for several reasons:
You need to return a function, not a boolean.
You should pass the arguments as-is, not wrapped in an array.
You should preserve the context (this keyword) that the function would have been called in.
I would implement it like this:
Function.prototype.not = function (context) {
var func = this;
return function() { return !func.apply(context || this, arguments); };
}
I return an anonymous function (function() { ... })
I call apply to call the original function in the current contexts with the actual arguments.
(EDIT) Free bonus: I added an optional context parameter which will override this for the callback.
I would probably do it like so (but perhaps with some sort of namespacing):
function not (x) {
return !x;
}
function id (x) {
return x;
}
function compose (/*funcs*/) {
var args = arguments.length
? Array.prototype.slice.call (arguments)
: [id]
;
return function () {
var val = args [args.length - 1].apply (null, arguments);
for (var i = args.length - 2; i >= 0; --i) {
val = args [i] (val);
}
return val;
};
}
[1,2,3,4,1,2,3,4].filter (compose (not, equalTo (2)));
Using your idea:
function equalTo(n) {
var fn = function(x) {
return n == x;
};
fn.not = function(x) {
return n != x; // use this for simpler conditions
return !fn.apply(this, arguments); // use this for more complex logic
}
return fn;
}
So your example would work:
[1,2,3,4,1,2,3,4].filter(equalTo(2).not) == [1,3,4,1,3,4]
Edit: You can write a helper function (better name to be found) so not doesn't need to be redefined every time:
function generateFnWithNot(fn) {
return function () {
var f = fn.apply(this, arguments);
f.not = function () {
return !f.apply(this, arguments);
}
return f;
};
}
So when you're defining your functions, you can define them as normal with the exception of wrapping a generateFnWithNot call:
var equalTo = generateFnWithNot(function (n) {
return function (x) {
return n == x;
};
});
equalTo(5) // resolves to function () { return n == 5; }
equalTo(5).not // resolves to function () { return n != 5; }

How do I wrap a function in Javascript?

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.
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);
Object.extend(Function.prototype, {
Object.extend in the Google Chrome Console gives me 'undefined'
Well here's some working example:
Boolean.prototype.XOR =
// ^- Note that it's a captial 'B' and so
// you'll work on the Class and not the >b<oolean object
function( bool2 ) {
var bool1 = this.valueOf();
// 'this' refers to the actual object - and not to 'XOR'
return (bool1 == true && bool2 == false)
|| (bool1 == false && bool2 == true);
}
alert ( "true.XOR( false ) => " true.XOR( false ) );
so instead of
Object.extend(Function.prototype, {...})
Do it like:
Function.prototype.extend = {}
Function wrapping in good old fashion:
//Our function
function myFunction() {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
function wrapper(fn) {
try {
return function(){
console.info('We add something else', Date());
return fn();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
The same in ES6 style:
//Our function
let myFunction = () => {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
const wrapper = func => {
try {
return () => {
console.info('We add something else', Date());
return func();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
Here is an ES6 style:
const fnOriginal = (a, b, c, d) => {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
return 'Return value from fnOriginal';
};
const wrapperFunction = fn => {
return function () {
try {
const returnValuFromOriginal = fn.apply(this, arguments);
console.log('Adding a new line from Wrapper :', returnValuFromOriginal);
} catch (ex) {
ErrorHandler.Exception(ex);
}
};
};
const fnWrapped = wrapperFunction(fnOriginal);
fnWrapped(1, 2, 3, 4);
The following wrapping utility takes a function and enables the developer to inject a code or wrap the original:
function wrap(originalFunction, { inject, wrapper } = {}) {
const wrapperFn = function(...args) {
if (typeof inject === 'function') {
inject(originalFunction, this);
}
if (typeof wrapper === 'function') {
return wrapper(originalFunction, this, args);
}
return originalFunction.apply(this, args);
};
// copy the original function's props onto the wrapper
for(const prop in originalFunction) {
if (originalFunction.hasOwnProperty(prop)) {
wrapperFn[prop] = originalFunction[prop];
}
}
return wrapperFn;
}
Usage example:
// create window.a()
(function() {
const txt = 'correctly'; // outer scope variable
window.a = function a(someText) { // our target
if (someText === "isn't") {
throw('omg');
}
return ['a', someText, window.a.c, txt].join(' ');
};
window.a.c = 'called'; // a.c property example
})();
const originalFunc = window.a;
console.log(originalFunc('is')); // logs "a is called correctly"
window.a = wrap(originalFunc);
console.log(a('is')); // logs "a is called correctly"
window.a = wrap(originalFunc, { inject(func, thisArg) { console.log('injected function'); }});
console.log(a('is')); // logs "injected function\na is called correctly"
window.a = wrap(originalFunc, { wrapper(func, thisArg, args) { console.log(`doing something else instead of ${func.name}(${args.join(', ')})`); }});
console.log(a('is')); // logs "doing something else instead of a(is)"
window.a = wrap(originalFunc, {
wrapper(func, thisArg, args) {
try {
return func.apply(thisArg, args);
} catch(err) {
console.error('got an exception');
}
}
});
a("isn't"); // error message: "got an exception"
The last example demonstrates how to wrap your function with a try-catch clause
As far as polluting the namespaces, I'm actually going to pollute them some more...
Since everything that happens in JS is initiated by an event of some kind, I'm planning to call my magical wrapper function from within the Prototype Event.observe() method, so I don't need to call it everywhere.
I do see the downsides of all this, of course, but this particular project is heavily tied to Prototype anyway, and I do want to have this error handler code be as global as possible, so it's not a big deal.
Thanks for your answer!

Categories

Resources