How to make thrown errors visible outside of a Promise? [duplicate] - javascript

This question already has an answer here:
catch reject from promise
(1 answer)
Closed 6 years ago.
I am using csv-parse for stream parsing. For each record, I need to call some function mapper.process(). Since the latter function returns a promise, a wrapped it with co and prefixed yield.
parser.on('readable', function() {
var record;
while (record = parser.read()) {
return co(function*() {
yield mapper.process(record);
});
}
});
Without the addition (removing lines 4, 6 and yield), everything works fine. However, using the parser as shown above, thrown errors are swallowed.
How to fix this?

The problem here is that any thrown error will disappear because there is no catch handler after the co function.
But more importantly, the return statement inside the while loop will cause the whole function to return, so if you have multiple records in the buffer, you won't reach them.
You can write the following code to make it work:
parser.on('readable', function() {
return co(function* () {
var record;
while (record = parser.read()) {
const result = yield mapper.process(record);
// do something with the result..
console.log('result is ', result);
}
})
.catch((err) => console.error(err));
});
BUT, please be aware that because you're dealing with asynchronous code inside the "readable" callback, you'll cause the function to return immediately. This behaviour will cause the "finish" event to be called by the parser at the end of the stream and probably before you've actually finished processing the data.

Related

Is there any way to break out of a function by running another function in JS

I am working on a simple project and I would like to create a simple helper function that checks for a error in a callback. If there is a error then it should break the whole function that called it. Code example:
//Makes call to database and tries to insert element
db.collection("data").insertOne(
{
key: 'some-data'
}, (error, result) => {
//Return error if something goes wrong - else error is empty
checkError(error, "Unable to load database");
console.log("Succes item added")
}
);
Note: Yes this is node.js but this whole principle could be repeated in js with other callbacks - very simple repeatable error principle.
So in the insertOne function the first argument is some data I am adding to the database. The second argument is the callback function that is called after this async operation is finished. It returns a error which I could just handle by adding this if statement to the callback:
if (error) {
console.error(error);
return;
}
Buuut thats disrespecting the dry principle (bc I write the exact same if statement everywhere with no syntax being changed except the message) and is also distracting when reading the callback function. Now my issue is in the function checkError() even tho I can just print the error with the message or throw the error, I dont actually have a way to break the original callback so that it doesnt cause any more havoc in my database. I will go on to promisify this callback which is a solution. BUT I want to know if there is a way to this in the way I presented it here. Note: I dont want to use the try catch block bc thats replacing a if statement with another two blocks.
My checkError function:
const checkError = function (error, msg = "Something went wrong") {
if (error) console.error(`${msg}: error`);
//Break original block somehow ¯\_(ツ)_/¯
};
If I were to compress my question it would be: how to break a function with another function. Is there any way to achieve this?
I don't think this is possible. But you could achieve something similar with this:
function checkError (error, msg = "Something went wrong") {
if (!error) return false;
console.error(`${msg}: error`);
return true;
};
db.collection("data").insertOne(
{
key: 'some-data'
}, (error, result) => {
//Return error if something goes wrong - else error is empty
if (checkError(error, "Unable to load database")) return;
console.log("Succes item added")
}
);
Things become easier when you use promises.
Often asynchronous APIs provide a promise interface, and this is also the case for mongodb/mongoose, where you can chain a .exec() call to execute the database query and get a promise in return. This gives you access to the power of JavaScript's async/await syntax. So you can then do like this:
async function main() {
// Connect to database
// ...
// Other db transactions
// ...
let result = await db.collection("data").insertOne({ key: 'some-data'}).exec();
console.log("Item added successfully");
// Any other database actions can follow here using the same pattern
// ...
}
main().catch(err => {
console.log(err);
});
The idea here is that await will throw an exception if the promise returned by .exec() eventually rejects. You can either put a standard try...catch construct around it to deal with that error, or you can just let it happen. In the latter case the promise returned by the wrapping async function will reject. So you can deal with the error at a higher level (like done above).
This way of working also removes the need for numerous nested callbacks. Often you can keep the nesting to just one of two levels by using promises.

problem in returning object from the .filter() function to another modules [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
//I tried to return messages from the .filter() to another modules. I am able to console.log() it but unable to return it. i tried returning object(manually created) from outside the .then() it worked. But when i tried to return it from inside .filter() it didnt work. is it a problem of asyn? please explain on the basis of this problem about how async/await to use here... p.s i have read some documentation about promises, async/await.. but am not clear enough to use it in practical way.
function loadChat() {
return model
.find()
.then((data) => {
data.filter((datas) => {
messages = datas.messages;
console.log(messages);
return messages;
});
})
.catch((err) => {
console.log(err);
return err;
});
// const ans = {
// name: "madhav",
// };
// return ans;
}
//calling modules code is here
messages = loadChat();
console.log("type of messages", typeof messages);
console.log(messages);
//emitting event to load previous chat
socket.emit("loadChats", loadChat());
//output
type of messages object
Promise { <pending> }
EDIT: I see the problem now. You need to properly pass data from the find function - It should look something like this:
model.find((data) => data.filter ... // The rest of your code)
Also, what kind of error message or console log are you getting?

catching exceptions while waiting for a promise in nodejs

I am writing a library in nodejs, that is wrapping another library. my code is something like this:
function wrapper(functionToWrap) {
return function(param1, param2) {
try {
return functionToWrap(param1, param2);
} catch(err) {
console.log(err);
throw err;
} finally {
finalizeWrapping();
}
}
}
the problem is that my finalizeWrapping function is a function that waits for promises that i collect (by placing some hooks before calling functionToWrap on some of the async apis it uses) to resolve, and only then acts, something like this:
function finalizeWrapping() {
Promise.all(pendingPromises).then(function(values) {
//finalize the wrapping
console.log('all promises fulfilled!');
});
}
the issue is that the error is thrown and node exits (this error should not be handled, since the wrapped function doesn't handle it) before all the promises are resolved and the then block is executed.
my question is: is there anything i can do to work around this, meaning throwing the error to the user appropriately and finish executing the then block, or do i have to change the way i hook the apis to be synchronous and not use a promise?
Thanks in advance to all the helpers :)
EDIT: an attempt to make my question clearer - functionToWrap is not my function, it is a function of a different library (and it can change - meaning i want my code to be able to wrap as many functions as possible). this function is allowed to use async apis (which i may be trying to monkeypatch), and basically it should have as least restrictions as possible - i want the user to be able to write any function and me being able to wrap it.
Not sure if the following can help, you may not have enough reputation to comment although I think you can comment on your own question and it's answers.
const wrapper = functionToWrap =>
function() {
//special type to indicate failed call to functionToWrap
const Fail = function(reason){this.reason=reason;};
//does not matter how many argument. Assuming functionToWrap
// does not rely on "this". If it does then also pass the
// object that functionToWrap is on and replace null with that object
return Promise.resolve(Array.from(arguments))
.then(
//if functionToWrap is on an object pass it to wrapper
// and replace null with that object
args=>functionToWrap.apply(null,args)
)
.catch(
//if functionToWrap throws an error or rejects we will catch it here
// and resolve with a special Fail type value
err=>{
console.log(err);
return new Fail(err)
}
).then(
//since promise cannot fail (its rejection is caught and resolves with Fail)
// this will always be called
//finalize should return Promise.all... and maybe not use a shared
// variable called pendingPromises, global shared mutable variables in async
// functions is asking for trouble
result=>finalizeWrapping().then(
()=>
//if functionToWrap rejected or thew the result will be a Fail type
(result && result.constructor === Fail)
? Promise.reject(result.reason)//reject with the original error
: result//resolve with the functionToWrap result
)
);
}

Is there a way to execute some code when a promise is fulfilled, independently from the outcome? [duplicate]

This question already has answers here:
ES6 promise settled callback?
(8 answers)
Closed 7 years ago.
I need to execute the go() method when the promise is fulfilled, even if there is an error. (I am talking to backend API, and I need to do some UI work when I have the server response, even if is a 404).
Now I do this way:
Try.method().then(()=>{
go();
}).catch({
go();
})
There is a better way to avoid repeating the method invocation?
There is a finally() callback which will be called no matter what the outcome is:
Try.method().then(()=>{
go();
}).catch({
go();
}).finally({
go();
});
Since you are using babeljs which doesn't appear to support the finally() callback you can probably get away with this:
Try.method().catch(()=>{
go();
}).then({
go();
})
Where you first catch an error if there is one, if not it will execute the .then() as usual.
There is a better way to avoid repeating the method invocation?
Not certain if interpret above portion of Question correctly ? Try defining a separate .then(go, go) chained to end of api calls
var go = function(data) {
console.log("go", data)
};
var p = function(args, val) {
return Promise[args](val)
};
p("resolve", 1).then(go, go);
p("reject", 0).then(go, go);
If can use jQuery, could try utilizing deferred.always()
var go = function(data) {
console.log("go", data)
};
var p = function(args, val) {
return $.Deferred()[args](val)
};
p("resolve", 1).always(go);
p("reject", 0).always(go);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

Javascript error stops code execution

Whenever an error occurs inside an event handler, it stops code execution entirely so the second event callback isn't called.
For example:
$(function() {
window.thisDoesntExist();
}
$(function() {
//Do something unharmful and unrelated to the first event
}
You can easily solve the problem in this (simplified) example by adding try/catch in both anonymous functions, but in reality these functions often add several other event handlers which in turn would require try/catch. I end up with very repetitive code stuffed with try/catch blocks.
My projects has a modular design where each feature is in a different JS (and gets concatenated during a build process). I'm looking for a more generic way to handle errors inside each feature so that the error doesn't stop code execution of the other features.
I already tried following solutions:
- window.onerror (even if you return true in this function, code execution is stopped)
- $(window).error() => deprecated and code execution stops
You could create a helper function to prevent duplication of the same boilerplate code.
function tryFunction(f, onerror) {
try {
if (typeof f == 'function') {
return f();
}
} catch (e) {
return onerror(e);
}
}
$(function() {
var result = tryFunction(window.thisDoesNotExist, function (error) {
alert('Whoops: ' + error);
});
});
I created a little demonstration. It's slightly different but the same idea.
You can simply call if (typeof myFunction == 'function') before calling myFunction()
And optionally wrap it in a generic function like said by Bart to have the choice to log an error in the console if your function does not exists.
If your webapp is huge with many interaction and JS, too many try catch could alter the global performance of your application.
I would try something like this with a wrapper which will handle the try catch for you (see below, or this jsfiddle : http://jsfiddle.net/TVfCj/2/)
From the way I'm (not, and not really) handling the this and the arguments, I guess it's obvious I'm beginning with js. But I hope you get the idea, and it is correct/useful.
var wrapper = {
wrap: function wrap(f) {
return function (args) {
try {
f.apply(null, args);
} catch (ex){
console.log(f.name+" crashed with args "+args);
};
};
}
};
var f1 = function f1Crashes(arg) {
return window.thisDoesntExist();
};
var f2 = function f2Crashes(arg) {
return window.thisDoesntExist();
};
var f3 = function f3MustNotCrash(arg) {
wrapper.wrap(f1)(arg);
wrapper.wrap(f2)(arg);
}
f3('myarg');
The try-catch pattern you mention attempting in your question is the correct way - you want try-catch blocks, not a way to silently truck through module errors (in general always be extremely careful handling exceptions globally and continuing, that way lies data corruption bugs you only find 6 months later).
Your real problem is this:
... in reality these functions often add several other event handlers which in turn would require try/catch. I end up with very repetitive code stuffed with try/catch blocks.
The fix for that is Promise. This is a new structure, native in most browsers but easily shimmed in the slow ones (ahem, IE), that gives you a standard way of managing both the event callback and the exception from the event.
With a Promise your code makes a promise to always do something: either resolve/succeed or reject/fail.
function moduleA() {
return new Promise(function (resolve, reject)
{
try{
var result = window.thisDoesntExist();
resolve(resolve); // Success!
}
catch(err){
reject(err); // Fail!
}
});
}
This is better because rather than nest try-catch blocks in each callback you can instead chain promises:
moduleA().
then(moduleB).
then(moduleC).
catch(errorHandler); // Catch any error from A, B, or C
You can also handle an error and continue:
moduleA().
catch(continuableErrorHandler). // Catch any error from A
then(moduleB).
then(moduleC).
catch(errorHandler); // Catch any error from B or C
You'll still need lots of try-catch blocks in callbacks, but anything that has been wrapped in a Promise can be treated in the same modular way.
Coming next in JS is async and await, but you can use them now with a transpiler. These use promises to make code that is much easier to read, and most importantly (for you) have a single try-catch at the top that gathers exceptions from the entire Promise chain.
This answer is already too long, but I've blogged about that in more detail.
TL;DR: If your problem is "very repetitive [event callback] code stuffed with try/catch blocks" try using Promise instead.
I found a solution. When using setTimeout, the code is executed in a seperate thread, therefor it won't break any other parts of the webpage.
$(function() {
setTimeout(function() {
window.thisDoesntExist();
}, 0);
});
$(function() {
setTimeout(function() {
//Do something unharmful and unrelated to the first event
alert("This passes")
}, 0);
});
In this example, the second function is run, even when the first one throws an error.
Here's a working example: http://jsfiddle.net/mathieumaes/uaEsy/

Categories

Resources