How to handle multiple errors thrown by an utility function? - javascript

I have a function examples(a,b,c,…). Each argument can throw an error. All of them are handled the same way. I guess examples([array]) would fall in the same category.
In my code I have something like that currently:
for (i = 0; i < len; i++) {
try { this.example(arg[i]) }
catch (e) { log(e) }
}
From an user perspective Id like to be able to see the errors of all arguments at once instead of fixing one and then discovering the next one etc. But I end up catching myself which seems, to me, not desirable for an utility function.
Is there a way to rethrow all errors at once?
What are the best practices?
If there's a standard, why is it being recommended?

Well you can throw pretty much anything, but rather than just a simple Array, you may find you have more maneuverability using a custom error type
function ErrorCollection(msg) {
this.name = 'ErrorCollection';
this.message = msg || '';
this.errors = [];
}
ErrorCollection.prototype = Object.create(Error.prototype);
ErrorCollection.prototype.constructor = ErrorCollection;
ErrorCollection.prototype.push = function (e) {
return this.errors.push(e);
}
// ...
var i, ec = new ErrorCollection();
for (i = 0; i < 10; ++i) {
try {
throw new Error('Error ' + i);
} catch (e) {
ec.push(e);
}
}
// do something with ec, e.g.
if (ec.errors.length) {
console.log(ec, ec.errors);
throw ec;
}
An example of stopping on the first error then validity checking the remainder
var i, a = [];
for (i = 0; i < arguments.length; ++i) {
try { // assume everything will work
this.example(arguments[i]);
} catch (e) { // our assumption was wrong
a.push({arg: i, val: arguments[i]});
for (++i; i < arguments.length; ++i) { // loop from where we left off
if (!this.valid_arg(arguments[i])) { // some costly test
a.push({arg: i, val: arguments[i]});
}
}
throw a; // throw the list of bad args up a level
}
}
If the validity test will be fast/isn't costly then you may consider doing it in advance of your main loop instead of waiting for the first error, as you should then be able to avoid try..catch at this level entirely.

Related

how to set default value in case of error

I'm learning React and I'm trying to render 10 pieces of data from a specific API.
This is a function I wrote for iterating through the fetched data and taking the title and the image:
for (let i = 0; i < 10; i++) {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs.src,
});
}
I don't know why but one of the images gives me that error:
index.js:1 TypeError: Cannot read property 'attribs' of undefined
Which stops the whole rendering.
I wanted to try to put a temporary placeholder image so the rest of the images can be loaded without any errors.
I thought about adding conditions into the image line inside the loop but it didn't work for me. What's the right way to do that?
If I wasn't clear enough please comment what wasn't clear and I'll try to describe it better.
If someMethod is synchronous (based on your code sample it should be) then you can wrap your code in try...catch block like so:
for (let i = 0; i < 10; i++) {
try {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs.src,
});
} catch (err) {
data.push({
title: 'placeholder',
image: 'placeholder',
});
continue;
}
}
Here's more cleaner version of the above:
for (let i = 0; i < 10; i++) {
let title = '';
let image = '';
try {
title = someMethod(allData)[i].children[0].data;
image = someMethod(allData)[i].attribs.src;
} catch (err) {
image = 'failed to load or something';
}
data.push({title, image});
}
for (let i = 0; i < 10; i++) {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs?.src ?? defaultSrc,
});
}
docs: Optional_chaining and Nullish_coalescing_operator
You can solve the null pointer exceptions in 2 ways.
Manually check for truthy values using ? or &&
Create a simple utility function
Point 1 will solve your problem, but however if you start using it everywhere throughout your code it may not look tidy. I'd recommend to go by creating a utility function as below.
export const getSafe = (fn, defaultValue=null) => {
try {
return fn()
} catch (e) {
return defaultValue
}
}
You can then use it anywhere like..
var result = getSafe(() => object1.data.key)
You can use it for accessing any type of values to any depth. You can also pass a default value as 2nd argument if required. by default it is set as null
var resultArray = getSafe(() => array1.data.values, [])
Just remember, the 1st value should be passed as a function.
So in your case...
for (let i = 0; i < 10; i++) {
data.push({
title: getSafe(() => someMethod(allData)[i].children[0].data, "Default Title"),
image: getSafe(() => someMethod(allData)[i].attribs.src, "placehoder_img"),
});
}
Implement the map function.
The for loop will give an error at your component
In react if you need to render elements don't implement the for loop
datas.map(......)

JS Set.has() returning false boolean value when item is present

I have written a recursive function that has a base case, but it is not terminating because of an if statement that reads the values in a set. timestamps.has() always returns false even when it "should be" returning true.
I am unable to track down the bug, and am wondering if I am doing something wrong that is simple, such as the scoping of the timestamps variable, I have already checked the values in the set and the values that are compared and they are in fact equivalent, so I am not sure what is wrong.
var timestamps;
trackFraud = async () => {
account = document.getElementById("account").value;
timestamps = new Set();
await fraudClimb(account, 0);
async function fraudClimb(account, theseTimestamps) {
var [frauds, theseTimestamps] = await findFraudByFromAccount.call(this, account, theseTimestamps);
if (frauds.length == 0) return;
for (var i = 0; i < frauds.length; i++) {
await fraudClimb(frauds[i], theseTimestamps[i]);
}
}
}
findFraudByFromAccount = async (account, timestamp) => {
events = await window.KYCinstance.getPastEvents('ReportedFraudB', { filter: {fromAccount: web3.utils.fromAscii(account)}, fromBlock: 0 });
var frauds = [];
var theseTimestamps = [];
for (let i = 0; i < events.length; i++) {
let values = events[i].returnValues;
if (timestamps.has(values.times)) continue; //THIS LINE IS NEVER FAILING
else {
timestamps.add(values.time);
theseTimestamps.push(values.time);
frauds.push(web3.utils.toAscii(values.fromAccount));
}
}
return [frauds, theseTimestamps];
}
It looks like you have a mismatch here:
extra 's'
/
if (timestamps.has(values.times)) continue;
else {
timestamps.add(values.time);
\
no 's' here
...
Depending on your values object structure, this might be crucial. Your has check will return false if these properties are not equal or if one of them does not exist.

Protractor: Can you delay the WebElement.sendKeys() globally onPrepare?

I am runing protractor on a slow machine and I need protractor to slow down each key press and each action. The action part is done, but how can I do the keyPress part?
I have a local solution with is:
function delay(el, value, newDelay) {
for (var i = 0; i < value.length; i++) {
browser.sleep(newDelay || browser.params.delay);
el.sendKeys(value[i]);
}
}
In onPrepare I was able to slow down each action with:
browser.driver.controlFlow().execute = function () {
var args = arguments;
if (arguments[1] === "WebElement.sendKeys()")
debugger;
origFn.call(browser.driver.controlFlow(), function () {
return protractor.promise.delayed(100);
});
return origFn.apply(browser.driver.controlFlow(), args);
};
but I don't know how to slow down the sendKeys, I belive I have to do something where I placed the debugger, but what?
Aparenty, the only solution I found, was to try and send at first the entire string and if it fails, send the keys one by one, and check again, so my code is something like this:
el.getAttribute('value').then(function (insertedValue) {
if (insertedValue !== value) {
el.clear().then(function () {
el.sendKeys(protractor.Key.END);
for (var i = 0; i < value.length; i++) {
browser.sleep(100);
el.sendKeys(value[i]);
el.sendKeys(protractor.Key.END);
}
if (tryNo < 1) {
el.getAttribute('value').then(function (insertedValue) {
if (insertedValue !== value) {
.......................
}
});
}
});
}
});

JavaScript Try Catch

I'm looking at some code on a website that hides / shows content on a click.
function expando() {
try {
if (document.getElementsByClassName) {
var e = document.getElementsByClassName("expandlink");
t = 0;
} else {
var e = document.querySelectorAll(".expandlink"),
t = 1;
};
if (null != e) {
for (var a = 0; a < e.length; ++a) e[a].onclick = function() {
return OpenClose(this), !1
};
if (1 == t)
for (var a = 0; a < e.length; ++a) {
var n = e[a].href,
r = n.indexOf("#"),
i = n.substr(r + 1),
l = document.getElementById(i);
l.className = l.className + " expandtargetIE8"
}
}
} catch (o) {}
}
function OpenClose(e) {
try {
var t = e.href,
a = t.indexOf("#"),
n = t.substr(a + 1),
r = document.getElementById(n);
r.className = "expandtarget" === r.className ||
"expandtarget expandtargetIE8" === r.className ?
"expandtargeted" : "expandtarget expandtargetIE8",
e.className = "expandlink" === e.className ?
"expandlink expandlinked" : "expandlink"
} catch (i) {}
}
window.onload = function() {
expando()
};
Here is the JS Fiddle.
https://jsfiddle.net/amykirst/3hbxwv1d/
I've never seen the JavaScript try...catch statement. I looked at some tutorials, and they all say that they are for error testing. Why would it be used here?
It doesn't look like the catch actually does anything.
Note: this code had been minified. I used an online tool to unminify it.
The try..catch block here is used for error handling. It's used here to allow the code to continue normal execution if an error does arise.
Not all browsers will support both document.getElementsByClassName and document.querySelectorAll. On a browser which doesn't support either, we'd get the following error:
Uncaught TypeError: document.querySelectorAll is not a function
...and further code execution would stop.
However with a try..catch block here, the code instead wouldn't alert us about the error at all (at least, not without inspecting o within the catch block). Execution would continue as normal. It's no longer an uncaught error, it's a caught error which simply has nothing done with it.
If in the same browser we're to adjust the above code to log o within the catch block:
... } catch (o) { console.log(o) }
The same message shown above would be displayed on the console, without the "uncaught" part:
TypeError: document.querySelectorAll is not a function(…)
Actually there are few real use case of try-catch.
Error handling : Your JS function/statements may throw error, like TypeError (Accessing undefined,null) , JsonParseError etc. Sometimes you need that to be handled, so that next set of statements has to be executed. If it is not handled, the JS engine will throw it and halts the function execution.
Getting meaningfull information from multiple function call stack: You may get into situation, in legacy codes, that function f1 is calling f2 and f2 calling f3 and so on. You may want to do some validation check and if validation fails you may like to stop the flow and show meaningfull error message. (like saying, invalid state). To handle this kind of scenario, we can handle with Custom Exception.
function ValidationError(message) {
this.name = "IocError";
this.message = (message || "Validation/System Error");
}
ValidationError.prototype = Error.prototype;
we can throw the custom error, if we see any validation error, like throw new ValidationError('Rule is missing...') in the function f3.
try {
...
} catch(e) {
if(e instanceof ValidationError) {
infoBox(e.message);
return false;
} else {
//This is not validation error, some other unknown issue has occurred
throw e;
}
}
We will use the above block to catch the exception in function f1 and if it is of type ValidationError, we'll display proper error message. If it as any other type we'll throw back for future debug purpose.

Understanding try..catch in Javascript

I have this try and catch problem. I am trying to redirect to a different page. But sometimes it does and some times it doesnt. I think the problem is in try and catch . can someone help me understand this. Thanks
var pg = new Object();
var da = document.all;
var wo = window.opener;
pg.changeHideReasonID = function(){
if(pg.hideReasonID.value == 0 && pg.hideReasonID.selectedIndex > 0){
pg.otherReason.style.backgroundColor = "ffffff";
pg.otherReason.disabled = 0;
pg.otherReason.focus();
} else {
pg.otherReason.style.backgroundColor = "f5f5f5";
pg.otherReason.disabled = 1;
}
}
pg.exit = function(pid){
try {
if(window.opener.hideRecordReload){
window.opener.hideRecordReload(pg.recordID, pg.recordTypeID);
} else {
window.opener.pg.hideRecord(pg.recordID, pg.recordTypeID);
}
} catch(e) {}
try {
window.opener.pg.hideEncounter(pg.recordID);
} catch(e) {}
try {
window.opener.pg.hideRecordResponse(pg.hideReasonID.value == 0 ? pg.otherReason.value : pg.hideReasonID.options[pg.hideReasonID.selectedIndex].text);
} catch(e) {}
try {
window.opener.pg.hideRecord_Response(pg.recordID, pg.recordTypeID);
} catch(e) {}
try {
window.opener.pg.hideRecord_Response(pg.recordID, pg.recordTypeID);
} catch(e) {}
try {
window.opener.window.parent.frames[1].pg.loadQualityMeasureRequest();
} catch(e) {}
try {
window.opener.pg.closeWindow();
} catch(e) {}
parent.loadCenter2({reportName:'redirectedpage',patientID:pid});
parent.$.fancybox.close();
}
pg.hideRecord = function(){
var pid = this.pid;
pg.otherReason.value = pg.otherReason.value.trim();
if(pg.hideReasonID.selectedIndex == 0){
alert("You have not indicated your reason for hiding this record.");
pg.hideReasonID.focus();
} else if(pg.hideReasonID.value == 0 && pg.hideReasonID.selectedIndex > 0 && pg.otherReason.value.length < 2){
alert("You have indicated that you wish to enter a reason\nnot on the list, but you have not entered a reason.");
pg.otherReason.focus();
} else {
pg.workin(1);
var n = new Object();
n.noheaders = 1;
n.recordID = pg.recordID;
n.recordType = pg.recordType;
n.recordTypeID = pg.recordTypeID;
n.encounterID = request.encounterID;
n.hideReasonID = pg.hideReasonID.value;
n.hideReason = pg.hideReasonID.value == 0 ? pg.otherReason.value : pg.hideReasonID.options[pg.hideReasonID.selectedIndex].text;
Connect.Ajax.Post("/emr/hideRecord/act_hideRecord.php", n, pg.exit(pid));
}
}
pg.init = function(){
pg.blocker = da.blocker;
pg.hourglass = da.hourglass;
pg.content = da.pageContent;
pg.recordType = da.recordType.value;
pg.recordID = parseInt(da.recordID.value);
pg.recordTypeID = parseInt(da.recordTypeID.value);
pg.information = da.information;
pg.hideReasonID = da.hideReasonID;
pg.hideReasonID.onchange = pg.changeHideReasonID;
pg.hideReasonID.tabIndex = 1;
pg.otherReason = da.otherReason;
pg.otherReason.tabIndex = 2;
pg.otherReason.onblur = function(){
this.value = this.value.trim();
}
pg.otherReason.onfocus = function(){
this.select();
}
pg.btnCancel = da.btnCancel;
pg.btnCancel.tabIndex = 4;
pg.btnCancel.title = "Close this window";
pg.btnCancel.onclick = function(){
//window.close();
parent.$.fancybox.close();
}
pg.btnHide = da.btnHide;
pg.btnHide.tabIndex = 3;
pg.btnHide.onclick = pg.hideRecord;
pg.btnHide.title = "Hide " + pg.recordType.toLowerCase() + " record";
document.body.onselectstart = function(){
if(event.srcElement.tagName.search(/INPUT|TEXT/i)){
return false;
}
}
pg.workin(0);
}
pg.workin = function(){
var n = arguments.length ? arguments[0] : 1;
pg.content.disabled = pg.hideReasonID.disabled = n;
pg.blocker.style.display = pg.hourglass.style.display = n ? "block" : "none";
if(n){
pg.otherReason.disabled = 1;
pg.otherReason.style.backgroundColor = "f5f5f5";
} else {
pg.otherReason.disabled = !(pg.hideReasonID.value == 0 && pg.hideReasonID.selectedIndex > 0);
pg.otherReason.style.backgroundColor = pg.otherReason.disabled ? "f5f5f5" : "ffffff";
pg.hideReasonID.focus();
}
}
I think your main problem is that you're swallowing exceptions, which is very bad. This is why "it works sometimes". Something is throwing an exception, and you're catching it, but then you're not doing anything else after that. At the very least I would display some sort of error message in your catch block.
A few other problems:
Are you sure you need those multiple try..catch blocks? The current assumption in your code is that each line that is wrapped in a try..catch is independent of the others, and execution can still proceed if something goes wrong in any one (or more) of those statements. Are you sure this is what you want? If so, there is definitely a better way of handling this.
If the statements are not independent of each other, and if a failure at any point means that execution cannot proceed, then you can wrap all of those statements in a single try..catch block and display an error message in the catch
Like I said before, swallowing exceptions is very bad! You're hiding the problem and not achieving anything. It also makes debugging extremely hard, because things will stop working and you will have no idea why (no exception, no logging, no error messages). Exceptions are used when something unexpected happens that interrupts normal program flow. It is something you definitely want to handle.
I think what you want can be done this way:
try {
if(window.opener.hideRecordReload){
window.opener.hideRecordReload(pg.recordID, pg.recordTypeID);
} else {
window.opener.pg.hideRecord(pg.recordID, pg.recordTypeID);
}
window.opener.pg.hideEncounter(pg.recordID);
window.opener.pg.hideRecordResponse(pg.hideReasonID.value == 0 ? pg.otherReason.value : pg.hideReasonID.options[pg.hideReasonID.selectedIndex].text);
window.opener.pg.hideRecord_Response(pg.recordID, pg.recordTypeID);
window.opener.pg.hideRecord_Response(pg.recordID, pg.recordTypeID);
window.opener.window.parent.frames[1].pg.loadQualityMeasureRequest();
window.opener.pg.closeWindow();
}
catch(e) {
console.log(e);
}
This way, if an exception occurs anywhere along those series of statements, the catch block will handle it.
Javascript also doesn't have true checked-exceptions. You can get around it by having a single try block, and inspecting the exception object that you receive*.
Expanding on what I talked about earlier, there are two ways of handling exceptions. The first way, like I showed earlier, assumes that when an exception happens, the code is in an invalid/undefined state and this therefore means that the code encountered an unrecoverable error. Another way of handling exceptions is if you know it is something you can recover from. You can do this with a flag. So:
try {
doSomething();
}
catch(e) {
error = true;
}
if(error) {
doStuffToRecoverFromError();
}
else {
doOtherStuff();
}
In this case the flow of your logic depends on an exception being thrown. The important thing is that the exception is recoverable, and depending on whether it was thrown or not, you do different things.
*Here is a somewhat contrived example that demonstrates checked-exceptions. I have two exceptions called VeryBadException and ReallyBadException that can be thrown (randomly) from two functions. The catch block handles the exception and figures out what type of exception it is by using the instanceof operator):
function VeryBadException(message) {
this.message = message;
}
function ReallyBadException(message) {
this.message = message;
}
function foo() {
var r = Math.floor(Math.random() * 4);
if(r == 2) {
throw new VeryBadException("Something very bad happened!");
}
}
function bar() {
var r = Math.floor(Math.random() * 4);
if(r == 1) {
throw new ReallyBadException("Something REALLY bad happened!");
}
}
try {
foo();
bar();
}
catch(e) {
if(e instanceof VeryBadException) {
console.log(e.message);
}
else if(e instanceof ReallyBadException) {
console.log(e.message);
}
}
It's good practice do something with the caught exceptions.
What's happening here is that if there's an error (say loading a page fails) an exception is thrown inside one of your try blocks. The corresponding catch block grabs it and says "that exception has been dealt with" but in actuality you've not done anything with it.
Try putting a print(e.Message); inside your catch blocks to find out exactly what error is causing the page not to load and then add code to your catch block to deal with this error.

Categories

Resources