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
Related
Ive been using the following code for ages to test the following code example.
function loadAccounts() {
return AccountCaller.loadAccounts()
.then(function(response){
AccountsModel.accounts = response.accounts;
})
.catch(function(error){
ErrorHandler.raise(error);
});
}
var spy= spyOn(mock, 'loadAccounts').andCallFake(function () {
return {
then: function (callback) {
return callback(response);
}
};
});
The above code works fine on the '.then' but i recently introduced the '.catch' and now my tests fails 'TypeError: Cannot read property 'catch' of undefined'.
Any ideas on how i can deal with the '.catch' element, if i remove it then the code test runs fine !!!
Cheers
In your spy of then you have return callback(response);, but your callback does not return anything, which is why you get the undefined in your error. The thing you're returning will need to at least have a catch method of some kind attached to it. You can test that with something like this:
var spy= spyOn(mock, 'loadAccounts').andCallFake(function () {
return {
then: function (callback) {
callback(response);
return {catch: function() {}};
}
};
});
^^ This isn't necessarily how I'd do that, but it should get you moving in the right direction. Consider returning the result of callback(response) wrapped in a Promise.
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')});
I am fairly new to using mocha and I ran into this bug. Please help me understand this behavior.
'use strict';
var flightMiddlewareMock = require(process.cwd() + '/test/mock/response/flightmock');
describe('Test Flights function: getTime', function(){
var mockData;
beforeEach(function(done){
mockData = flightMiddlewareMock.getValidData();
done();
}
it('getFlightDescription returns the full flight description', function(done){
contentUtils.loadContent({
'files': {
activity: '/flights/america'
},
'locality': "en_US"
}, function(err, bundle) {
var flightsMiddleware = new FlightsMiddleware(country, mockData.req, bundle);
console.log('inside content callback');
description = flightsMiddleware.getFlightDescription(mockData.results.body.items[0]);
assert.equal(description, "Boeing 777");
done();
}
});
});
Output looks like this
inside content callback
inside content callback
inside content callback
- Failure of test!
Question - I do not understand why in spite of using 'use strict' it does not complain about description not being declared.
Please note: If I do modify this to
var description = .....
it works viola! Am I missing something?
Thanks for your time!
Mocha will report the exception caused by trying to assign to an undeclared variable. If I run this:
"use strict";
it("foo", function (done) {
setTimeout(function () {
description = "foo";
done();
}, 1000);
});
I get the result:
1) foo
0 passing (1s)
1 failing
1) foo:
Uncaught ReferenceError: description is not defined
at null._onTimeout (test.js:5:21)
Now, I've used setTimeout which is a well-behaved function in that when the callback passed to it throws an exception, setTimeout does not prevent this exception from reaching the top of execution context. In other words, it does not swallow exceptions.
If you have a callback that throws an exception but this exception is swallowed by the code that called the callback, you'll get a test timeout but you won't know why because Mocha won't be able to detect the exception. It relies on the uncaughtException event, which is not emitted if the exception is swallowed.
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");
}
);
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.