How to trigger an early exit from outside function? - javascript

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!");
} );
}

Related

how to break parent function based on a child outcome in google app script?

How can I break the parent function depending from a child function's outcome as a way of checking everything in case something is not ok in a child function? I currently have the following:
function Parent() {
Step1();
Step2();
Step3();
}
and I would like to break the parent function if child function "Step1()" is not completed, for example.
I thought I could create a global variable as a flag, combined with an if statement within the parent function such that if the flag would change from "true" to "false" within the child function, the whole parent function would break, but this didn't work giving an error saying the "break is illegal". This is what I tried:
var flag = "true" // Global variable
function Parent() {
Step1(); //Within this child function, I have an "if" condition that sets flag "true"/"false" depending on the outcome
if (flag == "false") { //I was hoping this would read the incoming flag and trigger a break, if the flag was set to "false" in Step1();
}
Step2();
Step3();
}
Right now my script goes through all child functions even if Step1() is incorrect, and without a way to stop this sequence, I'll just keep getting undesirable results from the parent function.
I also thought that if I used "break;" at any point in the whole .gs file it would break the whole thing but it's not the case. If I run Step1() on its own and the "if" conditions activate the "break;" it breaks succesfully, but when I run the parent function it just keeps going onto the next function.
Thanks,
Nestor
To successfully break, add a return
The return statement ends function execution
if (flag == "false") { return; }
Alternatively, you could throw a error or play with try...catch
Live snippet:
let flag = 0;
function main() {
console.info("main1");
function step1() {
console.info('step1');
flag = 1;
}
function step2() {
console.info('step2');
}
step1();
if (flag) return; //stops execution
step2();
}
function main2() {
console.info("main2");
function step1() {
console.info('step1');
}
function step2() {
console.info('step2');
throw new Error('Step 2 fatal error');
}
function step3() {
console.info('step3');
}
try {
step1();
step2();
step3();
} catch (e) {
console.error(e.message);
}
}
main();
main2();
apply blow logic
let flag = true;
function(){
if (flag == "false") {
"false" in child1();
goto lineContinue
}
child2();
child3();
}
lineContinue: child4();

Possible Try/Catch prevents error from showing

The following check needs to be added to a large AngularJS application: Whenever a screen calls a specific global function (a()) to perform an operation, an if condition needs to be executed. If the check returns true, then everything is ok, otherwise the execution should stop and an error message (alert) should be shown to the user. This is achieved by throwing an error and decorating AngularJS's $exceptionHandler to catch that specific error.
Example:
app.factory('$exceptionHandler', function() {
return function (e, st) {
if (e instanceof MyErr) {
alert("An error occurred");
return;
}
}
});
class MyErr extends Error { /* */ }
function a() {
if (allWell) { /* everything's good */ }
else {
throw new MyErr("Failure");
}
}
Problem is, ~20 other modules around the application can invoke a():
Screen 1:
// ...
a();
alert("Success");
// ...
Screen 2:
try {
a();
} catch (e) {
// ...
}
alert("Success");
As can be seen, some screens will wrap the call to a() in a try/catch block, while others won't. As a result, the "Failure" message gets shown when Screen 1 makes a call, but when Screen 2 makes a call, the exception gets caught by the try/catch that was set up by the caller and "Success" message gets incorrectly shown.
With or without exceptions, how can alert("Success") (and subsequent code) be prevented from running (since there was an error detected earlier)?
Solution 1:
Put alert("Success"); in a().
function a() {
if (allWell) { /* everything's good */
alert("Success");
}
else {
throw new MyErr("Failure");
}
}
Solution 2:
Use Callback in a().
function a(callback = function(){}) {
if (allWell) { /* everything's good */
callback();
}
else {
throw new MyErr("Failure");
}
}
Screen 1:
// ...
a(function(){
alert("Success");
});
// ...
Screen 2:
try {
a(function(){
alert("Success");
});
} catch (e) {
// ...
}

Stop function execution from another function

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 */
}
}

JavaScript infrastructure such that propagated errors don't get lost

My group is starting a new project. We are thinking about organizing the JavaScript in such a way so that any JavaScript errors don't get lost but rather get caught and sent to the server to be logged. For namespacing I want to keep it simple so I'm using something like this:
var my_namespace = function() {
function myFunction(input) {
if (input < 0) {
throw "input must be positive";
}
return 'result';
}
return {myFunction: myFunction};
} ();
So now I can invoke my_namespace.myFunction(-22) but when the error will be thrown it will get lost. There will be many namespaces each one in it's own .js file (maybe somebody has a better idea about namespace schema).
So, my question is, how to like "surround" namespaces so that errors will not get lost?
Actually #Relic gave a good idea. I'm going to write below the code that will create the namespace "my_namespace" and surround the initialization by jQuery with try-catch:
var my_namespace = function() {
function init() {
throw "an exception during initialization";
}
return {init: init};
} ();
$(document).ready(function() {
try {
my_namespace.init();
} catch (e) {
// handle error
}
});
I'm going to experiment with what happens after it does initialization, that is, with the event handling.
Yep, just as I thought, event handling exceptions will not be caught. I'll research some more and return.
Two options for you:
Wrap Everything
You can wrap all of your code with try/catch blocks. This isn't as tedious as it sounds. There are two aspects of this: Wrapping your main code, and wrapping code that runs in response to events (user events, timer events, etc.). You can either do that manually, or you can give yourself a framework for doing it.
This doesn't have to be a pain at all. For instance, for the first part, just wrap a try/catch around your main code:
(function() { // (If you don't use scoping functions, just ignore this and the last line
try {
// Your code here
}
catch (e) {
reportException(e);
}
function reportException(exception) {
try {
// Do whatever you want to do to report the exception here.
}
catch (e) {
// Let the browser report it
throw 'Error handling exception: ' + exception;
}
}
})();
For the second part (catching exceptions in event handlers and code fired with setTimeout and similar), you can either always manually use try/catch blocks in all of your code (which is frequently what you want to do anyway), and possibly use a central function that wraps your event handlers to make sure uncaught exceptions are caught and handled, like this:
function makeHandler(handler) {
eventHandler.original = handler;
return eventHandler;
function eventHandler(event) {
try {
// Trigger the handler
return handler.call(this, event);
}
catch (e) {
// Handle event handler exception
reportException(e);
}
}
}
(There are more features you might add to that, but those are the basics.)
For public methods, you can use something quite similar to makeHandler:
function makePublic(method) {
publicMethod.original = method;
return publicMethod;
function publicMethod() {
try {
// Trigger the actual member
return method.apply(this, arguments);
}
catch (e) {
// Handle reporting the exception
reportException(e);
// Then probably re-throw it so the calling code
// sees it
throw e;
}
}
}
Bringing that all together, this code:
var Namespace = (function() {
var NS = {};
// Some setup
doSomething();
doSomethingElse();
if (/* Some condition */) {
doYetAnotherThing();
}
// Export public methods
NS.foo = foo;
NS.bar = bar;
function doSomething() {
var element = document.getElementById("foo");
// Note, next line could throw if element doesn't exist
element.addEventListener("click", function(event) {
// Handling click
var other = element.getElementsByTagName('input')[0];
element.innerHTML = other.value; // Could throw if `other` not there
}, false);
}
// ...other functions, including `foo` and `bar`...
// Return the namespace object
return NS;
})();
Turns into:
var Namespace = (function() {
var NS = {};
try {
// Some setup
doSomething();
doSomethingElse();
if (/* Some condition */) {
doYetAnotherThing();
}
// Export public methods
NS.foo = makePublic(foo);
NS.bar = makePublic(bar);
}
catch (e) {
reportException(e);
}
function doSomething() {
var element = document.getElementById("foo");
// Note, next line could throw if element doesn't exist
element.addEventListener("click", makeHandler(function(event) {
// Handling click
var other = element.getElementsByTagName('input')[0];
element.innerHTML = other.value; // Could throw if `other` not there
}), false);
}
// ...other functions, including `foo` and `bar`...
// ...`reportException`, `makeHandler`, `publicMethod`...
// Return the namespace object
return NS;
})();
So it's not that much impact.
You always want to use more targeted try/catch as part of your logic, but you can also use these global try/catch blocks to catch anything unexpected (like those silly bugs that sometimes slip into the catch block!), etc.
There are several advantages to this approach:
It works on all browsers.
You can throw things other than strings (more structured exceptions), and they'll still be
objects when you catch them.
If an error reaches the browser level, you know it's not in your code, or it's in your exception reporting code.
Use window.onerror
If for whatever reason the above isn't to your taste, a little-known feature of the browser environment is the fact that you can trap any uncaught error by assigning a function to window.onerror (live example described and linked below):
window.onerror = globalErrorHandler;
function globalErrorHandler(errorMsg, url, lineNumber) {
// Do something with the error here
}
This works in most browsers, but not all, and suffers from the fact that chaining these sorts of error handlers isn't natively supported (you have to do it yourself) and by the time the error reaches your code, it's already been turned into a string (a pain if you're using more structured exception objects).
Details on the MDC page for it, including how to play nice with others; slightly modified example:
function addWindowErrorHandler(handler) {
var previous = window.onerror;
window.onerror = function(errorMsg, url, lineNumber) {
var returnValue = false,
handled = false;
// Call the handler
try {
returnValue = handler(errorMsg, url, lineNumber);
}
catch (e) {
// Eat the error
}
// Hand off to previous
if (!returnValue && previous) {
try {
returnValue = previous(errorMsg, url, lineNumber);
}
catch (e) {
// Just eat it
}
}
// Done
return returnValue;
};
}
Just call that with a reference to your handler function, and have your handler function return true if the error was yours to handle, false otherwise.
To know whether the error is yours or not, you might consider putting a marker in the string (sadly, it'll be a string by the time it reaches the onerror handler, even if you threw some other object type). So you might use a worker function for the whole module that adds a marker, e.g.:
function myException(msg) {
return '*Marker* ' + msg;
}
Then
throw myException('cannot be negative');
and your handler would do
if (String(error).indexOf('*Marker*') >= 0) {
// It's ours
// ...handle it...
// Flag that we handled it
return true;
}
Unfortunately, even though you process the error, I'm not aware of any way to suppress it (the script still stops executing at that point).
You could even have Exception objects you construct that accept a message and a nested exception if you like. Just be sure to handle toString on them, because (again) by the time the error gets to the error handler, it's already been turned into a string.
Live example
I'd recommend a block of code that can monkey patch any function calls (nb untested):
(function (namespace) {
var addTryCatch = function (delegate) {
try {
delegate.apply(this, arguments);
} catch {
// standard code here
}
};
for (var propName in namespace) {
var prop = namespace[propName];
if (typeof prop === 'function') {
namespace[propName] = addTryCatch(namespace[propName]);
}
}
}(yourNamespace));
Any recursion could be added if necessary.
My Official answer:
<input type="button" id="btn" name="dont click me" value="dont click me" />
var _ns = { init: function() {
this.events();
},
events: function(){
$("#btn").on('click mouseover', function(event){
if(event.type != "mouseover"){
_ns.error.alert("Annnd you clicked me anyways");
}else{
_ns.error.console("nice mouseover skillz");
}
});
},
error:{
console:function (Error) {
console.log("Error: "+Error);
},
alert: function(Error){
alert("Error: "+Error);
}
}
};
$(document).ready(function() {
_ns.init();
});
After spending some time looking for the solution I came to the following conclusion. You must use window.onerror, there is no other way.

Javascript error handling with try .. catch .. finally

I have a suspicion that I'm using the finally block incorrectly, and that I don't understand the fundamentals of its purpose...
function myFunc() {
try {
if (true) {
throw "An error";
}
} catch (e) {
alert (e);
return false;
} finally {
return true;
}
}
This function will run the catch block, alert "An error", but then return true. Why doesn't it return false?
The finally block contains statements to execute after the try and catch blocks execute but before the statements following the try...catch statement. The finally block executes whether or not an exception is thrown. If an exception is thrown, the statements in the finally block execute even if no catch block handles the exception. more
The finally block will always run, try returning true after your try block
function myFunc() {
try {
if (true) {
throw "An error";
}
return true;
} catch (e) {
alert (e);
return false;
} finally {
//do cleanup, etc here
}
}
Finally blocks execute when you leave the try block. In your code this happens when you return false. That sets the return value to false and attempts to exit the function. But first it has to exit the try block which triggers the finally and overwrites the return value to true.
It is considered by many to be a good programming practice to have a single return statement per function. Consider making a var retval at the beginning of your function and setting it to true or false as appropriate throughout your function and then structuring the code so that it falls correctly through to a single return at the bottom.
function getTheFinallyBlockPoint(someValue) {
var result;
try {
if (someValue === 1) {
throw new Error("Don't you know that '1' is not an option here?");
}
result = someValue
} catch (e) {
console.log(e.toString());
throw e;
} finally {
console.log("I'll write this no matter what!!!");
}
return result;
};
getTheFinallyBlockPoint("I wrote this only because 'someValue' was not 1!!!");
getTheFinallyBlockPoint(1);
Run this on your browser's console and it might give you the answer you're looking for.

Categories