Neither catch statement of promise/block is executing - javascript

I have this code in a worker.
var cBtnStore = {
a: function(){}
};
Now notice there is no b key in there.
I then have a function in my worker. It does this:
function run() {
...
self.postMessageWithCallback(function() {
cBtnStore.b(); ////// there is no b key, this should prevent going to the return
});
...
return promise; // returns a promise
}
var gCB = {};
self.postMessageWithCallback = function(aMsgArr, aCB) {
var gCBID++;
aMsgArr.push(gCBID);
gCB[gCBID] = aCB;
self.postMessage(aMsgArr);
}
self.onmessage = function(msg) {
var aCBID = msg.data.pop();
gCB[aCBID].apply(msg.data);
};
I then do this in the worker:
try {
run().then(x=>{}, y=>{}).catch(z=>{console.error('promise caught')});
} catch(err) {
console.log('runComplete threw');
}
console.log('result:', result);
What actually happens - This logs to console the return value of runComplete() which is "result:" [Promise object]. Neither catch nor .catch statements not execute.
What I was expecting should have happened - It should have triggered the catch statement of the promise or of the try-catch block.
My question - Is there anyway to make this catch?

When you write
run().then(x=>{}, y=>{}).catch(z=>{console.error('promise caught')});
your argument y=>{} actually means "eat all errors". If you want to see errors, you should write
run().then(x=>{}).catch(z=>{console.error('promise caught')});

Related

Error handling in Q promise

I'm a bit confused understanding Q promise error handling. Let's say I have the following functions (for demonstration only):
function first() {
console.log('first');
var done = Q.defer();
done.resolve('first');
return done.promise;
}
function second() {
console.log('second');
var done = Q.defer();
done.resolve('second');
return done.promise;
}
function third() {
console.log('third');
var done = Q.defer();
done.resolve('third');
return done.promise;
}
function fourth() {
console.log('fourth');
var done = Q.defer();
done.resolve('fourth');
return done.promise;
}
function doWork() {
return first().then(function() {
return second();
}).then(function() {
return third()
}).then(function() {
return fourth();
});
}
doWork().catch(function(err) {
console.log(err);
});
Everything went fine.
Now that if in second, third or fourth function, I've got some errors (thrown by an async call for example), I could catch it gracefully.
For example, if in second, third or fourth function, I add:
throw new Error('async error');
The error is caught. Perfect!
But what makes me confused is that if the error is thrown in first function, the error is not caught and that breaks my execution.
Please someone tell me why or what I am doing wrong?
Thanks a lot!
Only exceptions in then callbacks are caught by promise implementations. If you throw in first, the exception will bubble and would only be caught by a try-catch statement.
That's exactly why asynchronous (promise-returning) functions should never throw. Instead, reject the promise you're returning (done.reject(…) or return Q.reject(…)). If you don't trust your function, you can use Promise.resolve().then(first).… to start your chain.
Wrap the logic that can break in a try block and reject the promise with the error in the catch block.
var def = q.defer();
try {
// sync or async logic that can break
}
catch (ex) {
q.reject(ex);
}
return def;

Having if-else condition inside promises chains

I have a promises chain and inside some points I have if-else condition like the following:
.then(function() {
if(isTrue) {
// do something returning a promise
} else {
// do nothing - just return
return;
}
})
.then(function() {
...
})
Honestly I don't like this pattern. I feel it wrong. I mean using just a plain return without anything. Do you have some idea to make look different this code?
That else { return; } part can simply be completely omitted without changing the code's meaning:
.then(function() {
if (isTrue) {
// do something returning a promise
}
})
Functions do return undefined anyway by default.
I guess you have tested the code. And recognized that this is not working like you expected. Let me explain you:
function getPromise() {
callSomeFunctionWhichReturnsPromise().then(function(result) {
return result; // You hope, that this will be logged on the console? nope, you have to do it here instead.
console.log('logged in the promise', result); // This will work
});
}
var result = getPromise();
console.log(result); // undefined!!!
you could instead do this:
function getPromise() {
return callSomeFunctionWhichReturnsPromise();
}
var result = getPromise();
result.then(console.log); // will call console.log(arguments)

In JS, how do I catch errors thrown by user-defined functions' asynchronous calls?

I'm writing a library that takes user-defined functions. I don't have control over what they do, but I want to catch all errors that they cause.
They might also make asynchronous calls like setTimeout, which might throw Errors. I want to catch those errors too.
For example—
// Suppose this is passed as an argument to the module
var userFunction = function() {
setTimeout(function() { throw Error("fail") }, 200);
}
// This is module code
try {
userFunction();
} catch (e) {
console.log("Caught error");
}
—fails with an error and prints a stack trace. The catch doesn't trigger.
I can see how this happens: The error is thrown from the function passed to setTimeout, which is called after the try-catch has passed, in a different context.
How do I work with that? Is it even possible?
If given a function that might call setTimeout or other asynchronous processes within it, how can I catch errors they might throw?
You can use window.onerror to catch all error
try {
setTimeout(function() { throw Error("fail") }, 2000);
} catch (e) {
console.log("Caught");
}
window.onerror = function (){
document.body.innerHTML = "Test";
}
or you can use try catch inside async method
setTimeout(function() {
try {
throw Error("fail");
} catch (e) {
console.log("Caught");
}
}, 2000);
You can use Promises.
With jQuery, something like:
var dfd = jQuery.Deferred();
setTimeout(function() {
dfd.reject("some error msg");
}, 1000);
$.then(dfd.promise()).then(function() {
//blank, this is success callback
}, function(msg) {
//throw your error
});
Full doc: https://api.jquery.com/deferred.promise/
EDIT: can use any Promise implementation. Such as kriswowal/q
https://github.com/kriskowal/q
You don't need to include jQuery. You can use javascripts built in Promise object:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype
you have:
y = x;
x returns a promise:
function() {
...
return promise;
}
All of the asynchronous calls in x are layered:
x is last async handler:
x = function () {
...
// a is second to last async success handler etc..
var j = new Promise (a);
j.then(function() {
// a returned resolve
if (some successful condition) {
resolve(what ever arguments you want to pass y);
} else {
reject(what ever arguments you want to pass y);
},
function (e) {
// error returned by a
reject(e);
}
);
return j;
};
then you can do:
y.then(function() {},
function() {
console.log("Caught");
}
);

Silent exceptions in Q:then callback?

I have some issue with calling function of null variable in 'then' callback of Q.promise.
The first call (without Q using) will show an error, but while the second (wuth Q using) doesn't.
Small example:
var Q = require('q');
var nul = null;
var exp;
(function (exp) {
var A = (function () {
function A() {
};
A.prototype.foo = function () {
var d = Q.defer();
d.resolve('Hello, world');
return d.promise;
};
A.prototype.bar = function (i) {
switch (i) {
case 0:
/**
* That's all ok, "TypeError: Cannot read property 'qqq' of null"
*/
console.log(nul);
nul.qqq();
console.log('ok');
break;
case 1:
/**
* it's not ok, I see only result of "console.log(nul)", line 29
*/
this.foo().then(function () {
console.log(nul);
nul.qqq();
console.log('ok');
});
break;
};
};
return A;
})();
exp.A = A;
}) (exp || (exp = {}));
exp.a = new exp.A();
// You should run functions SEPARATELY!!!
exp.a.bar(0); // in that case: that's all ok, "TypeError: Cannot read property 'qqq' of null"
exp.a.bar(1); // int that case: it's not ok, I see only result of "console.log(nul)", line 29
I don't have any idea how to solve it
The reason why you're not seeing the second error on the console is because Q catches all errors and lets you handle them separately.
You can handle an error in then() by chaining with a catch() function, in your example this can be done this way:
this.foo().then(function () {
console.log(nul);
nul.qqq();
console.log('ok');
}).catch(function(error) {
// do something with error
console.log(error);
});
You can get this behavior also by using a try/catch block inside then() like this:
this.foo().then(function () {
try {
console.log(nul);
nul.qqq();
console.log('ok');
} catch (e) {
console.log(e);
}
});
Old answer
Here are a few options for catching errors in JS/node.js:
Try/Catch blocks
These work like in their Java/C# equivalent, wrap each of the calls you make with a try block and catch an error, handling it in the catch block
try {
exp.a.bar(0);
} catch(e) {
console.log(e);
}
You can also add finally blocks, check the type of an exception/error and so on, you can read more about it on the MDN page
Node.js uncaughtException handler
In node, you can catch all uncaught errors, which will stop your program, by binding a callback to the uncaughtException event like this:
process.on('uncaughtException', function (e) {
console.log('Error: ' + e);
});
This isn't always the best thing to do in a program, but if you really don't want to stop the execution, this is an option.
Finally, I recommend giving a look to this official article for best practices about handling errors in node.js

Best practice to handle exception when using Q.promise

I have the following method:
module.exports.getId = function(someObject) {
var myId = null;
return Q.Promise(function(resolve, reject, notify) {
// Loop through all the id's
someObject.user.player._id.forEach(function (id) {
if (id.root == "1.2.3.4.5.6") {
myId = id.extension;
}
});
resolve(myId);
});
};
This method works great as long as someObject exists and has the attributes user.player._id.
The problem i'm having is that if someObject is null or does not have all the appropriate nested attributes, an exception is thrown and the promise is never resolved. The only way I actually see the exception is if I have a .fail on the calling function, but that still doesn't actually resolve the promise.
Example of how I currently can see the exception:
myLib.getId.then(function() {
// something
}).fail(function(err) {
console.log(err);
});
I know 2 ways to get around this problem, but i'm not sure which, if either is the best way to handle something like this.
Option 1 (use try/catch inside my Q.promise):
module.exports.getId = function(someObject) {
var myId = null;
return Q.Promise(function(resolve, reject, notify) {
try {
// Loop through all the id's
someObject.user.player._id.forEach(function (id) {
if (id.root == "1.2.3.4.5.6") {
myId = id.extension;
}
});
} catch(e) {
reject(e);
}
resolve(myId);
});
};
Option 2 (explicitly check if someObject.user.player._id exists):
module.exports.getId = function(someObject) {
var myId = null;
return Q.Promise(function(resolve, reject, notify) {
ifi(someObject.user.player._id exists..) {
// Loop through all the id's
someObject.user.player._id.forEach(function (id) {
if (id.root == "1.2.3.4.5.6") {
myId = id.extension;
}
});
resolve(myId);
} else {
reject('invalid object');
}
});
};
Option 1 seems to smell funky to me because i'm using try/catch inside of a promise. Option 2 solves my problem, but any other unexpected exceptions will not get caught.
Is there a better way I should be handling this?
Your first example has a few problems:
When you catch an exception, you are rejecting the promise, then resolving the promise. That's breaking the promise contract; You can get around that by calling resolve within the try, not outside.
By using try/catch, you could be swallowing unintended errors. That is you are assuming that the only error would come from someObject.user.player._id not existing. That may be true at the moment, but it's not guaranteed to remain true as your code evolves.
By testing exactly for the known error condition, you know you won't be swallowing unexpected errors. Therefore, I would use your second example.

Categories

Resources