I have the following example:
function foo1 (callback) {
if (!foo2(callback)) {
return;
}
console.log("Doing something");
/* do something */
}
function foo2 (callback) {
return callback ();
}
foo1 (function () {
console.log ("Hello World!");
});
I want to remove the if from foo1. Can I stop foo1 execution calling foo2? I am looking for something like this:
function foo1 (callback) {
foo2(callback); // calling foo2 this way I want to prevent
// the console.log below to be executed
console.log("Doing something");
/* do something */
}
Is there any way to do this?
Note that I don't want to throw an error. I just want to call the callback function and to stop the function execution.
Use case
Instead of this:
function a (options, callback) {
callback = callback || function () {};
if (typeof callback !== "function") {
callback = function (err) { console.log (err); }
}
if (!options.someField || options.someField.constructor !== Object) {
return callback ("someField should be an object");
}
/* do something */
}
I want to have:
function a (options, callback) {
validateFunction (callback, callback);
validateObject (options, callback);
validateObject (options.somField, callback);
/* do something */
}
If one of the validate* functions fails it should send the error via callback and stop a function execution.
If you can use promises:
function a (options) {
return validateObject(options).then(function(){
return validateObjecT(options.somField);
}).then(function(){
return validateObjecT2(options.somField);
}).then(function(){
return validateObjecT3(options.somField);
}).then(function(){
return validateObjecT4(options.somField);
}).then(function(){
/*do something*/
});
}
var validateObject = Promise.method(function(object) {
// Because this is inside Promise.method, thrown error
// will be equal to return Promise.reject(new Error("invalid"));
if (typeof object !== "object") throw new Error("invalid");
});
Alternatively function a can be also done like this:
function a (options) {
// If any validation fails, the do something is skipped
// and the code resumes at the next .catch() with the validation
// error passed as parameter
return Promise.all([
validateObject(options),
validateObject2(options),
validateObject3(options),
validateObject4(options),
validateObject(options)
]).then(function(){
/*do something*/
})
}
a({}).then(function() {
// Validation succeeded and everything was done
}).catch(function(e) {
// Validation or something else failed, e is the rejection error
});
Btw don't use strings as errors, a string is not an error.
That is, never do:
throw "foo";
callback("foo");
reject("foo") // When using promises
Instead do:
throw new Error("foo");
callback(new Error("foo"));
reject(new Error("foo")) // When using promises
There is a way, use throw
function foo2(callback) {
// do what you want to do
throw true;
}
And then catching it
try {
foo1();
}
catch (e) {
// if false, real error,
}
But it appears at a strange design. I hope that you have a valid reason and that it's clear to others whom is reviewing your code in the future.
I would use if statements:
function a (options, callback) {
if (!validateFunction (callback)) return;
if (!validateObject (options, callback)) return;
if (!validateObject (options.somField, callback)) return;
/* do something */
}
where the validateFunction function does not necessarily need 2 parameters if you call it always from such a scenario and the validate... functions always return a boolean with the result of the validation AND calling the callback in case of error.
function validateObject (options, errorCallback) {
if (!options.someField || options.someField.constructor !== Object) {
errorCallback("someField should be an object");
return false;
}
return true;
}
As many purists say, building an execution flow using try catch is not the right thing to do. There is also the performance issue. Using try catch is less performant then the control statements (e.g. if)
And there is though a try catch version that is faster and produces less code but I still don't prefer it because it is less clear in the code:
function a (options, callback) {
try {
validateFunction (callback);
validateObject (options);
validateObject (options.someField);
catch (err) {
callback(err);
return;
}
/* do something */
}
function validateObject (options, errorCallback) {
if (!options.someField || options.someField.constructor !== Object) {
throw "someField should be an object";
}
}
take a boolean for your function
function foo1(callback, exe) {
if (exe) {
foo2(callback);
} else {
console.log("Doing something");
/* do something */
}
}
Related
These are some of my functions, I need to write a common function to see if functions are running without error. I tried with try/catch method. But I could only do that individually on each function.
function fisrt(){
console.log("First");
};
function second(){
console.log("Second");
}
function third(){
console.log("Third");
}
fisrt();
second();
third();
I was writing each function inside the try-catch. Is there a way I can write a common try-catch for all the functions.
try {
(function first() {
console.log("ffgdf")
})();
}catch (e) {
console.log( "won't work" );
}
You could define a wrapper function, that takes your desired function as a parameter, and wraps it in a try catch.
function wrapper(fn) {
try {
fn();
} catch(error) {
console.error(error);
}
}
Then given your original functions:
function first() {
console.log("First");
};
function second() {
console.log("Second");
}
function third() {
console.log("Third");
}
You can test each one by using your wrapper function:
wrapper(first);
wrapper(second);
wrapper(third);
Without needing to add try catch to each function.
Regarding the introducing sentence of the accepted answer two years ago ...
You could define a wrapper function, that takes your desired function as a parameter, and wraps it in a try catch.
... this part could be covered with (an) abstraction(s) where one also can provide the (different) handling of an invocation failure (the catch and exception clause).
If one does, for instance, provide functionality that wraps a function/method in way that does not only provide the try catch but also takes the exception handling into account, one can easily accomplish tasks, like the one asked by the OP for, which are mainly about programmable approaches for automatically creating and processing lists of functions/methods that are going to be invoked whilst suppressing unintended/unexpected invocation failures.
The following example does implement afterThrowing and afterFinally, two method modifier methods, each processing the original function/method with an exception handler as its first argument.
Making use of the provided abstraction(s) the approach itself boils down to writing reduce functionality which processes an array of functions by invoking each function with its own set of arguments and collecting its invocation success state ...
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>
In case of you wishing to get a "throwed" exception, you can use the Promise.all.
function parent() {
function first() {
console.log('First');
throw new Error('First error');
}
function second() {
console.log('Second');
}
function third() {
console.log('Third');
}
return Promise.all([
first(),
second(),
third(),
])
}
parent()
.then(result => console.log(result))
.catch(error => console.error(error))
I'm trying to create a function that's responsible for checking a boolean and exiting early with a warning, if true.
Here's example of what i'm trying to achieve:
function warnAndDie(shouldDie) {
if(shouldDie) {
console.log("go away, i'm dying!");
// TODO: some code to cause the calling function to exit early
}
}
function triggerTheWarnAndDie() {
shouldWarnAndDie(true);
console.log("I should never run!");
}
function dontTriggerTheWarnAndDie() {
shouldWarnAndDie(false);
console.log("I should run!");
}
What can i do so that warnAndDie is able to cause the calling functions to terminate early?
thank you
You have several options. I'll list the two very basic ones for you:
Return a value (probably boolean) and return early from you caller depending on the initial return value
function shouldWarnAndDie(shouldDie) {
if(shouldDie) {
console.log("go away, i'm dying!");
return true;
}
return false;
}
function triggerTheWarnAndDie() {
var hasDied = shouldWarnAndDie(true);
if (hasDied) return;
console.log("I should never run!");
}
Throw an exception
function shouldWarnAndDie(shouldDie) {
if(shouldDie) {
throw "Go away, i'm dying!";
// or cleaner:
// throw new dyingException("Go away, i'm dying!");
}
}
function triggerTheWarnAndDie() {
try {
shouldWarnAndDie(true);
console.log("I should never run!");
}
catch(err) {
console.log(err+" He's dead Jim!");
}
}
There are more advance mechanics which are probably out of scope for you right now, but LINQ's nice answer about callbacks and promises is definitely worth a look.
This can be achieved with basic exception handling. Here I have created a custom exception which can be caught using a try catch statement.
function shouldWarnAndDie(shouldDie) {
if(shouldDie) {
throw new DyingException();
}
}
function triggerTheWarnAndDie() {
try {
shouldWarnAndDie(true);
} catch(err) {
console.log(err.message);
return;
}
console.log("I should never run!");
}
function dontTriggerTheWarnAndDie() {
try {
shouldWarnAndDie(false);
} catch(err) {
console.log(err.message);
return;
}
console.log("I should run!");
}
// custom Exception handler
function DyingException() {
// do some custom exception handling here
return new Error("Go away, I am dying!");
}
triggerTheWarnAndDie(); // Go away, I am dying!
dontTriggerTheWarnAndDie(); // I should run!
Here is a JsFiddle Example
use the
return;
keyword to exit
*This is just a quick workaround. You may want to look into error checking and exceptions...
I'd suggest using promises but its not supported natively in all browsers. We can use callbacks where the code inside the callback only gets executed when warnAndDie allows it to execute.
function warnAndDie(shouldDie, fn) {
if(shouldDie) {
console.log("go away, i'm dying!");
// TODO: some code to cause the calling function to exit early
return;
}
fn();
}
function triggerTheWarnAndDie() {
shouldWarnAndDie(true, function () {
console.log("I should never run!");
} );
}
function dontTriggerTheWarnAndDie() {
shouldWarnAndDie(false, function () {
console.log("I should run!");
} );
}
I have a JavaScript class that is meant to help deal with promises. First you add functions to an array, then it executes them pops them and calls itself to do the next one. At the end of the array it resolves that promise. My hope was to then propagate the resolution all the way up the stack of recursive calls. This will allow you to force multiple asynchronous functions to run sequentially using a simple set of commands. furthermore employ logic to modify the flow of the ansync functions.
function Sequencer() {
this.functionSequence = [];
this.addFunction = function (func) {
this.functionSequence.push(func);
}
this.getFunctionSequence = function () {
return functionSequence;
}
this.executeAll = function () {
var functionList = this.functionSequence;
var deferred = $q.defer();
if (functionList.length > 0) {
functionList[0]().then(function (result) {
if (result) {
functionList.splice(0, 1);
executeAll().then(function (resultInner) {
if (resultInner == true) {
deferred.resolve(true);
} else {
deferred.resolve(false);
}
});
} else {
functionList = [];
deferred.resolve(false);
}
});
} else {
deferred.resolve(true);
}
return deferred.promise;
}
}
I am getting ReferenceError: 'executeAll' is undefined
in this script, on the recursive call line "executeAll' just after the splice
the first function in the array is being executed(I was testing it with a modal pop up) and when it resolves it hits the splice, then it throws the error right on the executeAll line. Am I defining the function incorrectly? Am I calling it correctly as a recursive function?
use this.executeAll - assuming this will be correct, which it wont, so you'll need to account for that as well ... something like var self = this at the top of executeAll, then call self.executeAll
this.executeAll = function() {
var functionList = this.functionSequence;
var deferred = $q.defer();
var self = this; // save reference to this
if (functionList.length > 0) {
functionList[0]().then(function(result) {
if (result) {
functionList.splice(0, 1);
// need to use self here because "this" is not the "this" we want
self.executeAll().then(function(resultInner) {
if (resultInner == true) {
deferred.resolve(true);
} else {
deferred.resolve(false);
}
});
} else {
functionList = [];
deferred.resolve(false);
}
});
} else {
deferred.resolve(true);
}
return deferred.promise;
};
The reason this is not the this you "want" is due to how this works in javascript - there is plenty on info on stack exchange about using this - I'll find and link a good answer shortly
I offer this alternative code
this.executeAll = function() {
return this.functionSequence.reduce(function(promise, item) {
return promise.then(function(result) {
if (result) {
return item();
}
else {
throw "Fail"; // throw so we stop the chain
}
});
}, Promise.resolve(true))
.then(function(result) {
this.functionSequence = []; // clear out the added functions
return true; // fulfilled value is true as per original code
}.bind(this), function(err) {
this.functionSequence = []; // clear out the added functions
if (err == "Fail") {
return false; // convert the "Fail" to a fullfilled value of false as per original code
}
else {
throw err; // any other error - re-throw the error
}
}.bind(this))
};
I am getting an error that I do not understand. I am calling async.waterfall with an array of functions. The function is 'shortened' for clarity.
FabricCommand.prototype.do = function (callback, undoArray) {
var self = this;
if (undoArray === undefined) {
undoArray = [];
}
undoArray.push(self);
callback(null, undoArray);
};
I create the array as listed below: doCommands is an array and the objects are added as such:
doCommands.push(fabricCommand.do.bind(fabricCommand));
the waterfall setup:
async.waterfall(
doCommands,
function(err, undoCommands){
if (err) {
// do something ...
}
else {
console.log('we succeeded with all the do commands... and there are '
+ undoCommands.length
+ ' in the undoCommands but we will disregard it...');
}
}
);
Now when I run this code, the first time through the FabricCommand.do function, I allocate the undoCommands array and I add one to it, next time through I get, where I try to add the array element, the following error:
undoArray.push(something);
^ TypeError: Object function (err) {
if (err) {
callback.apply(null, arguments);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.setImmediate(function () {
iterator.apply(null, args);
});
}
} has no method 'push'
Can anyone see what I am doing wrong?
The function that is executed by async.waterfall must have the following signature:
function(arg, callback) { … }
or, with multiple arguments:
function(arg1, arg2, callback) { … }
In your case, you simply inverted the two parameters:
FabricCommand.prototype.do = function (callback, undoArray) { … }
callback received the value intended to be stored in undoArray, and undoArray received the value intended for the callback, i.e. a function: that's why you encountered this weird error (function […] has no method 'push').
You need to put the parameters in the correct order:
FabricCommand.prototype.do = function (undoArray, callback) { … }
A second issue is that the first function of the waterfall receives only one parameter: the callback (because there is no value to be received, as it is the first function of the waterfall). A solution is to check the number of arguments:
if (Array.prototype.slice.apply(arguments).length === 1) {
callback = undoArray;
undoArray = undefined;
}
Here is a working gist.
Given this code:
var something = function(callback) {
if(condition) {
Mongoose.findOne(id, function(err, doc) {
if(doc) {
callback(doc);
} else {
callback();
}
});
} else {
callback();
}
}
How would I rewrite it in a cleaner way so that 'callback' is just called in one place. I assume I can wrap this entire thing somehow and do that - I've seen it but cannot get it quite right.
Since you said there are complex steps to call the callback, try the below
var something = function(callback) {
var callCallback = function(doc){
//do all other things you want to do to call the callback
callback(doc);
};
if(condition) {
Mongoose.findOne(id, function(err, doc) {
if(doc) {
callCallback(doc);
} else {
callCallback();
}
});
} else {
callCallback();
}
}
var something = function (callback) {
var f = function (e, d) { callback(d) };
if (condition) {
Mongoose.findOne(id, f);
} else {
f();
}
}
my reasoning is that if d is false then we still can pass it on to callback and it will be the same almost as passing no arguments at all.