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.
Related
I have two functions to accept input from the CLI using process.stdin. When one of the function is completed accepting input data, similar such function is invoked but when the control is shifted to the called function, calling function is still been referred and executed which is generating contradicting results.
var ar = [];
var a = 0;
test();
function test2(){
console.log("TEst 2");
process.stdin.setEncoding('utf8');
process.stdin.resume();
process.stdin.on('data',function(b){
if(ar.length < a)
{
ar.push(b.replace("\n",""));
}
else
{
test3();
}
});
}
function test3()
{
for(var t in ar)
{
console.log("ar["+t+"]: " + ar[t]);
}
process.exit();
}
function test()
{
process.stdin.setEncoding('utf8');
process.stdin.resume();
process.stdin.on('data',function(dat)
{
dat = dat.replace("\n","");
if(isNaN(dat))
{
console.log("This is an invalid number");
}
else
{
a = parseInt(dat);
console.log("calling test2");
test2();
}
});
}
test() invokes test2(). Everytime the data is accepted in test2(), this data is validated for isNaN in test() and produces console.log("This is an invalid number"); for any non-numeric input which is a valid data.
Please find the result below.
deepakbilikere:~/workspace $ node goodnumber.js
2
calling test2
TEst 2
a
This is an invalid number
b
This is an invalid number
c
This is an invalid number
ar[0]: a
ar[1]: b
I would like to execute this piece of logic without the use of any external packages.
Can someone please help me in understanding the code flow as well as improve the code??
One thing that pops out immediately, is that you're attaching multiple listeners to the data event for stdin. Note that the previous listener in test() doesn't go anywhere while your attaching a second one in test2(). You could achieve some improvements by using once() that only listens to the event one time and then unregisters itself. But you have to be careful how the stream resuming behaves then (research this).
process.stdin.once('data', ...)
Also, can you tell us what is it that you're aiming to do, so we can help you better. Now the goal gets lost in the midst of nested functions.
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!
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 want to log all errors in my browser side JavaScript code. I saw a lot of discussions here and on the net about window.onerror and it is clear it does not work cross browser. So, I plan to wrap top level entry functions with try - catch. Trouble is, a lot of my code is event handlers. I have not tested it yet, but I am pretty sure that no matter where the event handler function is defined, a thrown error will fire out directly to the browser implementation that calls it, not to event function declaring code. My only choice is to declare throw, catch and error log calls in every error handler even the tiniest anonymous one. I don't like that one bit.
A possible solution:
I use one method to cross browser register events. I can modify it to do something like this:
function registerEventHandler(object, handlerRef) {
var wrapperFunction = function(evt) {
try {
handlerRef(evt);
} catch {
logError(error);
}
registerEvent(object, wrapperFunction);
}
There is one major problem with that implementation. I often keep references to event handler function in order to deregister them later. This will not work as the function registered as the handler will be the wrapper, not the original one. The answer to this is to implement a wrapper -> wrapped mapping object and use it on unregister.
The question:
I dare you JavaScript magicians to come up with more clever solution than that. Maybe it could be done by somehow augmenting the event handler function before registration? This is a far as my JavaScript knowledge goes. What about yours?
I often keep references to event
handler function in order to
deregister them later. This will not
work as the function registered as the
handler will be the wrapper, not the
original one.
Why is this a problem? once the function is wrapped in the error handling, you dont really care about the original function anymore. The wrapper keeps a reference to your original function, and the wrapper is what is registered, and the wrapper is what needs to be unregistered.
Just keep a reference to your wrapper function you generate because its the only one that matters.
Also making it it's own function will make this pattern far more reusable
var protectErrors = function(fn) {
var that = this;
return function() {
try {
fn.apply(that, arguments);
} catch(error) {
logError(error);
}
};
};
var registerEventHandler = function(object, handlerRef) {
var wrapperFunction = protectErrors(handlerRef);
registerEvent(object, wrapperFunction);
};
protectErrors(fn) will return a function that runs the original in whatever context it was called in, and forwarding any number of arguments.
I'm using the HTML5 Web Database API and I have a function that checks to see if the app needs to go and perform it's setup phase :
this.setupRequired = function() {
var status;
try {
this.db.transaction(function(tx) {
tx.executeSql("SELECT * FROM settings", [], function (tx,result) {
if (result.rows.length == 0) {
status = true;
} else {
status = false;
}
}, function(tx) {
status = true;
})
});
} catch (e) {
return true;
}
return status
}
I'd like to return true or false based on whether there is data in the settings table or not (or if the settings table doesn't exist). The status var isn't getting set, I'm guessing this is due to scope issues and the anonymous callback functions. I'm pretty sure I need to use a closure here to correct the issue but can't quite get it right.
I'd like to return true or false based on whether there is data in the settings table or not
You can't. It is not known whether there is data in the settings table at the time the setupRequired() method has to return. This will only be known when the SQL database has performed the query and invoked the callback function. That happens only after setupRequired() and the functions that led to it being called have all exited, returning control to the browser.
That's the whole point of the callback function being passed to executeSql(). The function is not executed right away, so status will not have been touched by the time return status is reached. What's more, any exceptions that occur inside the callback functions will not cause the catch(e) block to be executed, because the try...catch block will long have been exited by the time the function that was defined inside it is actually called. So this try...catch is effectively useless.
This is ‘asynchronous’ coding. Just because some code is below a function, doesn't mean the function's going to execute first.
You could probably set status as a property of the object or another object of your own making.
You could also check at each stage what 'this' is or what value status has using firebug.
Hmm, I don't have any experience using this API but it appears that you are trying to set a value in a callback function and then return that value from the outer function. Assuming the callback is asynchronous, this will not work. I think your best bet is to change your code to something like:
this.setupRequired = function() {
try {
this.db.transaction(function(tx) {
tx.executeSql("SELECT * FROM settings", [], function (tx,result) {
if (result.rows.length == 0) {
doYourSetupFunction();
} else {
//don't;
}
}, function(tx) {
doYourSetupFunction();
})
});
} catch (e) {
doYourSetupFunction();
}
}
So that the setupRequired function is reponsible for checking and triggering the setup.