Let's say I have function below
var isallow = false;
function checkToAllow(){
if(isallow == false)
// stop execution of calling method( parent method)
}
function showMEVal(){
checkToAllow();
console.log("I am here because I am allowed");
}
so basicaly, showMEVal() method will first check that execution further is allowed or not, if it is allowed it will continue further, else it will exit.
This is to be common functionality to a number a function where it needs to be first checked whether it should be continue or not.
I dont want to explicitly work with returned values from checkToAllow() method, like
function showMEVal(){
if(checkToAllow() == true)
console.log("I am here because I am allowed");
}
I was thinking to use event.stopImmediatePropagation(); but it does not seems it will work.
Please advise
Thanks
The normal way to handle this is to throw an exception in the child function. You can read a brief description of exception handling in JavaScript at w3schools, here: http://www.w3schools.com/js/js_errors.asp.
So for your example, you'd have:
var isallow = false;
function checkToAllow() {
if(isallow == false)
throw CustomAbort(); // Can be anything: object or basic data type
}
function showMEVal(){
try{
checkToAllow();
}
catch (err) {
return;
}
console.log("I am here because I am allowed");
}
What makes this useful is that you only have to have the try... catch... construct at the very top level of your JavaScript, and only once. Then, deep down in your processing you can simply have:
function deepFunction() {
checkToAllow();
console.log("I am here because I am allowed.");
console.log("I'm not sure what happens if I'm not allowed, because it's taken care of by checkToAllow(), and by the top level error handling!")
}
You could probably also just throw anything from checkToAllow and provided nothing else is catching that error, it would propagate all the way up as a JavaScript error and stop the rest of your processing... but that's obviously not best practice, because no one wants JavaScript errors in their page!
Related
I'm used to throwing an instance of some error class and having them be caught somewhere down the line in the app, to account for user error.
An example might be validating the username:
function validateUsername (username) {
if (!/^[a-z0-9_-]{3,15}$/.test(username)) {
throw new ValidationError('Please enter 3-15 letters, digits, -, and/or _.');
}
}
$('#username').blur(function () {
try {
validateUsername($(this).val());
} catch (x) {
$('<p></p>').addClass('error').text(x).insertAfter(this);
}
});
But now I'm realizing that I can't use these same practices for asynchronous calls. For example:
function checkUsernameAvailability (username) {
$.get('/users/' + username).done(function () {
// Done = user returned; therefore, username is unavailable
// But I can't catch this error without resorting to something gross
// like window.onerror
throw new ValidationError('The username you entered is already in use.');
});
}
I could make checkUsernameAvailability accept a callback and/or return a promise and have it execute said callback with the availability of the username.
$('#username').blur(function () {
checkUsernameAvailability(username, function (available) {
!available && alert('The username you entered is already in use.');
});
});
But part of what makes exceptions so powerful is that they can bubble up the stack until they get caught, whereas if I had another function that called another function that called checkUsernameAvailability, I'd need to pass the result of this callback manually all the way until I get to the place where I want to handle it.
What are some of the alternative methods for passing errors up the stack? I can think of some of these, but none of them are as clean as native exceptions:
Passing a flag, or the ValidationError instance, to a callback (Node.js approach could work too, passing an error or null as the first argument, and the data as the second); but then, if I don't want to handle it at that point in the stack, I need to pass the error up manually
Or passing 2 callbacks to the checkUsernameAvailability function, a success callback and an error callback; this seems to have the same drawbacks as the previous point
Triggering a "ValidationError" event so I can listen anywhere, but make sure to return false; in the handler so it doesn't execute higher in the stack; however, this pollutes the event namespace and could make it unclear as to which event listener will be executed first; plus, it's difficult to trace an event to its origin using the console
in principal it is like this
function Exception (errcode) {
this.code = errcode;
}
...
try {
...
throw new Exception('alpha');
...
} catch (e) {
if (e.code === {something}) {
}
}
If it helps, I recently took the first release of the Rogue game written for UNIX in C and rewrote it for javascript to work in a browser. I used a technic called continuation to be able to wait for key entry by the user because in javascript the are no interrupts.
So I would have a piece of code like this:
void function f() {
// ... first part
ch = getchar();
// ... second part
}
that would be transformed in
function f() {
// ... first part
var ch = getchar(f_cont1);
return;
// the execution stops here
function f_cont1 () {
// ... second part
}
}
the continuation is then stored to be reuse on a keypressed event. With closures everything would be restarted where it stoped.
I need to be able to run a bunch of code if a statement is successful. If javascript had a try/catch/else then I would put all the code in the else and be done with it. I don't want to use a Boolean to mimic the else in try/catch/else. My understanding is that try can handle an error but can't IF do the same? If so, I'll have to use the IF but I don't want my program to crash if the QueryInterface fails. So my question is, if the QueryInterface fails, then the else will be executed in the IF below correct? If so then I guess the only reason to use a try/catch is to snag the error condition.
existing method:
try {
channel = subject.QueryInterface(Ci.nsIHttpChannel);
} catch(err) {
booSuccess = false;
intErrorCount++
}
if (booSuccess == true) {
...bunch of stuff...
}
proposed method:
if (channel = subject.QueryInterface(Ci.nsIHttpChannel)) {
...bunch of stuff...
} else {
intErrorCount++
}
No, throwing an exception (which you catch with the first snippet) is very different from returning an error code (channel == 0, which the second snippet checks). They do not do the same.
What you might do to avoid that boolean variable is
try {
channel = subject.QueryInterface(Ci.nsIHttpChannel);
...bunch of stuff...
} catch(err) {
intErrorCount++
}
but that would also raise the error count if an exception happens in the bunch of stuff.
No you can't simply replace the try/catch with an if/else. If a line throws an error, the javascript interpreter will stop execution of that script.
I am working on small part of calculation code. I need to identify whenever recursive occur in javascript/jQuery and i need to terminate that recursive.
Is there any api to support this in javascript/jQuery?
You could implement your own recursive protection. There is nothing built into jQuery that would natively support preventing recursion.
function myFunc(arg) {
// if this function already executing and this is recursive call
// then just return (don't allow recursive call)
if (myFunc.in) {
return;
}
// set flag that we're in this function
myFunc.in = true;
// put your function's code here
// clear flag that we're in this function
myFunc.in = false;
}
myFunc.in = false;
You could also turn the boolean into a counter and allow recursion only up to a certain number of levels.
FYI, because JS is single threaded, this should only be an issue that might need protection if your function takes some sort of callback from code that isn't yours. If it's all your own code, then you should just make sure your own code won't cause this sort of problem.
Here's a little more foolproof version that protects the counter in a closure so it can't be manipulated outside the function:
var myFunc = (function() {
var inCntr = 0;
return function(args) {
// protect against recursion
if (inCntr !== 0) {
return;
}
++inCntr;
try {
// put your function's code here
} finally {
--inCntr;
}
}
})();
Note: this uses a try/finally block so even if your code or any code you call throws an exception the counter is still cleared (so it never gets stuck).
Another dodgy trick. If you use something like .bind(this) for recursion or if you use arrow function, it won't work.
boom();
function boom () {
if(arguments.callee === arguments.callee.caller) {
console.log('no recursion will happen');
return;
}
boom();
}
Simple solution could be a flag in a parameter
boom2();
function boom2 (calledRecursively) {
if(calledRecursively) {
console.log('no recursion will happen');
return;
}
boom2(true);
}
I could explain my problem but it is likely easier to demonstrate it...
If you take a look at http://jsfiddle.net/XxT2B/ you'll see my issue. I am having trouble figuring out how to pass an action to a function. You'll see what I mean.
Please note that the action could be different based on what calls the function. The action may be an alert on time and something different the next.
Here is my code...
function abc(action)
{
//Do a bunch of stuff first and then do the action sent to this function
alert('This function is named "abc"');
//This is the part I do not know how to do.
//The action might be an alert or something totally different so I can't just pass text
//I need to know how to execute the action passed.
action;
}
abc('alert("I like pizza")');
You can pass a function as a parameter to another function.
function abc(action)
{
//Do a bunch of stuff first and then do the action sent to this function
alert('This function is named "abc"');
action();
}
abc(function(){
alert("I like pizza");
});
You can pass a function into abc(), but be sure to sanitize
function abc(action)
{
alert('This function is named "abc"');
if(typeof(action) == "function") { //sanitize
action();
}
}
abc('alert("I like pizza")'); //will execute without a problem
abc(50); //will not run, since 50 is not a function
The good way:
Pass it as a function:
function abc(action)
{
//Do a bunch of stuff first and then do the action sent to this function
alert('This function is named "abc"');
action();
}
abc(function(){alert("I like pizza")});
the bad way (if your actions need to be strings):
function abc(action)
{
//Do a bunch of stuff first and then do the action sent to this function
alert('This function is named "abc"');
eval(action);
}
abc('alert("I like pizza")');
The second way is not advised because eval causes issues. It can run arbitrary code that can cause unexpected side effects, prevents compiler optimizations, and leads to difficulty debugging (since it can literally do anything depending on what you pass it). More on why eval is bad here.
But it will run an arbitrary string as javascript code like you were asking.
You just need to instantiate a function:
abc(function() { alert("I like pizza"); });
edit and then to call it, you use the value of your parameter exactly as if it were a function name (because, well it is!):
action();
You can use the eval method:
function abc(action)
{
//Do a bunch of stuff first and then do the action sent to this function
alert('This function is named "abc"');
eval(action);
}
abc('alert("I like pizza")');
And that's that.
Don't know what JavaScript version supports this syntax but you also can try:
function abc(action) {
if (typeof(action) != 'function')
return;
action();
}
abc(() => console.log('A B C'));
Just wondering how to test that a prototype is available based on its name.
For instance:
var node = new window[className];
console.log('test');
doesn't print anything if the className provided doesn't match a prototype that's been made available.
So testing:
if(! window[className]) {...}
make nothing to happen, the execution just stops, no breakpoint available past that point.
How can I handle this case?
Thanks!
If you want something to happen when className is not available, just use a simple else statement:
if(! window[className]) {
...
} else {
alert("No truthy property '"+className+"' was found on the window object");
throw new Error("something bad happened");
// whatever
}