I'm using an ID3 tag reader library https://github.com/43081j/id3 & the example function to call is in this format...
id3(this.files[0], function(err, tags) {
console.log(err, tags);
});
It works great for most files but from time to time there is an error like this
Uncaught URIError: URI malformed
I've tried to wrap this function in a try...catch to catch the error like this
try {
id3(file, function(err, tags) {
if (err) throw err;
console.log('tags .. ' + tags);
});
}
catch (e) {
console.log('caught it!');
}
But in fact the error still manages to remain uncaught.
I think it might be to do with the fact that the function is asynchronous, but am really struggling to understand how to prevent this and catch the error.
Ultimately I want to wrap the entire function in a promise, something like this:
return new Promise(function(resolve, reject) {
try {
id3(file, function(err, tags) {
if(err) throw err
resolve(tags);
});
}
catch (err) {
reject('blank');
}
}
but no matter what I try the reject method never gets called on an error.
Thanks!
Related
I'm trying to handle a function if it throws an error: create.js
function Apple() {
createDB() //function that saves into db
}
createDB.js
function createDB() {
const Info = new collection(data)
Info.save()
}
Suppose createDB function throws an error when required field in the db is not present. I want to handle such errors.
I tried:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch{
function that handles error
}
}
and I also tried:
function createDB() {
return new Promise((resolve, reject) => {
if some condition met{
const Info = new collection(data)
Info.save()
}else{
reject(error)
}
})
}
But it still doesn't goes to the catch block. I'm relatively new to the topic so any suggestions will be really helpful. Basically I want to handle the errors if a function throws error, and it should go to catch block.
You are actually not following the correct syntax. Check out the sampe one:
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
}
Your updated code with try-catch should follow the above syntax:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch (error) {
function that handles error
// here you should log errors or use the logging lib
}
}
Also, if you are using promises, you can follow this approach:
function createDB() {
return new Promise((resolve, reject) => {
if (condition) {
const Info = new collection(data);
Info.save().then(data =>{ resolve(data)})
.catch(e => {console.error(e)}) // handle this promise also
}
else {
reject(error);
}
})
}
Also, you need to understand when to use try-catch block and when to use promises. The try, catch blocks are used to handle exceptions (a type of an error) when the code is synchronous. You should use Promises only for asynchronous functions and nothing else.
Use this sample piece of code
Within try block we write our code which we want to execute
If any error occur controller goes to catch block
In catch block we also receive error
try {
//Here write your code which you want to execute
return true
} catch (error) {
//if there is an any error controller will come into this block and show error
console.error(error);
return false
}
I must connect to a LDAP server and find user based on a specific ID.
I've decided to use ldapjs module.
I managed to create my client and bind him so I can search for an user with success.
My problem is, as I only use async/await, that I don't understant how to handle error in callbacks... For example with this simple code from ldapjs library :
public static async search(searchOptions: SearchOptions) {
LdapService.bind()
LdapService.getClient()?.search('ou=*****,ou=***,dc=****,dc=****', searchOptions, function (err, res) {
ifError(err)
res.on('searchEntry', function (entry) {
// ----------------------
// an error came from here
throw new Error('test')
// ----------------------
console.log('entry: ' + JSON.stringify(entry.object));
});
res.on('searchReference', function (referral) {
console.log('referral: ' + referral.uris.join());
});
res.on('error', function (err) {
console.error('error: ' + err.message);
});
res.on('end', function (result) {
console.log('status: ' + result?.status);
});
})
}
LdapService.getClient() is a singleton method that return the result of createClient -> works fine
LdapService.bind() is a method that just bind with the server with correct credentials -> works fine
I just can't manage to handle my error "test"... How am I supposed to handle it?
Is the search method really async?
Can I do it the async/await way? :P
PS: the DN string ("ou=,ou=,dc=,dc=") is hidden due to security reasons and the code works great without throwing an error ;)
For anyone passing here and struggling with callback like me, here the "fix" I found :
public static async search(searchOptions: SearchOptions) {
// wrapping the all thing in a Promise that can be in a try/catch -> error will be handled there
return await new Promise((resolve, reject) => {
LdapService.getClient()?.search('ou=****,ou=****,dc=****,dc=****', searchOptions, function (err, res) {
if (err) {
// handle connection error I guess ?
reject(err)
}
res.on('searchEntry', function (entry) {
try {
// -------------
// Same test as before
throw new Error('test')
// -------------
resolve(JSON.stringify(entry.object))
} catch (err) {
// error must be catched to call reject method !
reject(err)
}
});
res.on('error', function (err) {
// handle API error when looking for the specific ID I guess ?
reject(err)
});
})
})
}
What solved my problem? Wrapping the all thing in a Promise.
All the "res.on" methods before were something like Promise listeners. So the all method search (the one inside mine) was a sort of asynchronous call.
Now I can call resolve/reject methods to return data and error.
Also, I can call my static search method the async/await way.
When you're not familiar with callbacks... ^^"
Please take into consideration that similar questions have been asked on SO and I went through most of them.
I am making a RESTful service that needs querying the DB to get the data. I wrote the code that queries the database correctly but does returns undefined all the time. The code is here:
function returnAll(){
ModuleDBService.find({},function(err,data){
if(err){
console.log('Error occured while retrieving the documents!');
}
return data;
});
}
I was exporting the module using:
module.exports = {
getAll:returnAll
};
After digging SO a lot, I discovered that I will need to use callback to get the data. I went through many examples and tried to apply a similar technique to my code, the modified code looked like this:
function getAllFromDatabase(callback){
ModuleDBService.find({},function(err,data){
if(err){
console.log('Error occured while retrieving the documents!');
}
callback(returnAll(data));
});
}
function returnAll(data){ return data;}
and then returning it in the similar fashion as above.
But now I am getting error that ModuleDAO.getAll is not a function (I am using var ModuleDAO = require('path to the database service').
I tried many variations of the code, went through a couple of videos on YouTube, all of them either lead to returning undefined, or return to the above stated error. If anyone could fix the code and throw light on this whole callback thing (Or could provide solid documentation to understand it), it'll be a great help.
Thanks.
EDIT: After all the extremely helpful answers, here is a summary:
Callbacks cannot return data, pass the function (the callback function) that you want your program to call with the data. In my case, it was my router returning the data.
Here is the corrected code:
function returnAll(callback) {
ModuleDBService.find({}, function (err, data) {
if (err) {
console.log("Error while retrieving the document!")
callback(null);
}
callback(data);
});
}
I used this code in my router as:
mainAPIRouter.post('/api/module', function (req, res) {
try {
moduleDAO.getAll(function(data){
res.status(200);
res.json(data);
});
} catch (error) {
res.status(500);
return res.send("Invalid request");
}
});
Thanks to all those who helped! :)
You are close. You don't need the returnAll() function, and you need to export getAllFromDatabase and pass a callback to it:
function getAllFromDatabase(callback){
ModuleDBService.find({},function(err,data){
if(err) {
console.log('Error occured while retrieving the documents!');
}
callback(data);
});
}
module.exports = {
getAllFromDatabase: getAllFromDatabase
};
Then, when you want to use it, you need a callback function:
dataModule.getAllFromDatabase(callbackHandler);
function callbackHandler(dataFromDatabase) {
// this function will be executed when ModuleDBService executes the callback
console.log(dataFromDatabase);
}
A small detail: if err is Truthy, you should not execute the callback:
if(err) {
console.log('Error occured while retrieving the documents!');
} else {
callback(data);
}
You want to simply call the callback() with the data you need as an argument. You are making things much more complicated by passing another function into the callback. Try something like:
function returnAll(callback) {
ModuleDBService.find({}, function(err, data) {
if (err) return callback(err)
callback(null, data);
});
}
returnAll(function(err, data)) {
// it's customary for callbacks to take an error as their first argument
if (err) {
console.log('Error occured while retrieving the documents!');
} else {
// use data here!!
}
}
As previous answers mentioned, you can use a callback. You can also use a promise if you prefer:
function returnAll(){
return new Promise(function(resolve, reject) {
ModuleDBService.find({},function(err,data){
if(err){
console.log('Error occured while retrieving the documents!');
reject(err);
}
resolve(data);
});
});
}
You would then use something like this to access it:
returnAll()
.then(data=> {console.log(data); })
.catch(err=> { console.log(err); });
*Edit: since you want to use a callback, thought I'd add my $0.02 there as well. The most streamlined approach would be to just use the callback you're passing in with the ModuleDBService.find, without the ad-hoc function. But it's good to verify that callback actually is a function, and if not to make it one...makes your code more fault-tolerant.
function returnAll(cb){
if(typeof cb!=='function') cb = function() {};
ModuleDBService.find({},cb);
}
I am attempting to open a 3rd party generated PDF that I know will fail occasionally. I am trying both pdf2json and pdfreader, and am encountering the same issue, which I'm not sure if it how I am attempting to handle the libraries in a promise.
When I receive an PDF, I would like to open it, to ensure that it is a valid PDF before passing it on for processing.
I am doing it like so:
function printRawItems(filename, callback){
new pdfReader.PdfReader().parseBuffer(filename, function(err, item) {
if (err) {
callback(err);
} else if (!item) {
callback();
} else if (item.text) {
callback(null, item)
} else if (item.page){
console.log("page =", item.page);
callback(null, item);
} else if (item.x){
console.log([item.x, item.y, item.oc, item.A, Math.floor(item.w), item.text].join("\t"));
callback(null, item);
} else {
console.warn(item);
}
});
}
function isValidPdf(buffer) {
return new Promise((resolve, reject) => {
printRawItems(buffer, function(err, item){
if (err) {
return reject(err);
} else if (item) {
return resolve(item);
}
return reject();
})
}).catch(err => {throw err})
}
The buffer being passed in to the "isValidPdf" is from an http request.
Now from what I can tell the callback I'm passing into the parseBuffer appears to get run twice. Once when the file is opened (and so item is "file"), and a second when it is parsed. After the first pass the promise in "isValidPdf" is resolved and the callback being passed in is never called, so it isn't rejected. The second run of the parseBuffer callback displays errors, which throws the exception, but by that time the promise is resolved and bad things happen.
Am I misunderstanding how the callbacks work, or are these libraries doing something wrong, and I should open a support ticket?
You're not misunderstanding how callbacks work. Just using them in the wrong way. I had a quick look at pdf2json and it seems you first create the parser, then do .parseBuffer() and wait for events to fire, e.g.:
function printRawItems (buffer, cb) {
const parser = new PDFParser()
parser.on('pdfParser_dataError', errData => {
cb(errData.parserError)
})
parser.on('pdfParser_dataReady', pdfData => {
cb(null, pdfData)
})
parser.parseBuffer(buffer)
}
I am trying to convert my old callback style functions to async await. However I can't understand how can I catch unhandled exceptions.
For example let's say I have a function
apiCall(input, function(error, result) {
if (error) {
console.log(error);
} else {
console.log(result);
}
});
I converted to Promise
function test1(input) {
return new Promise(function(resolve, reject) {
apiCall(input, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
Then I call it
test1(4)
.then(function(result) {
console.log('Result: ' + result);
})
.catch(function(errorr) {
console.log('My Error: ' + errorr);
});
Even though I try to return error, sometimes this function crashes. Let's say disk error, JSON parsing error etc. Some error that I didn't handle. I can only catch those errors with
process.on('uncaughtException', function(error) {
console.log('uncaughtException' + error);
});
Is there a way for me to catch all kinds of error with async await?
EDIT: Here is the full github repo for you to try
https://github.com/tosbaha/promise
Run node testme.js and see that it crashes and exception handler doesn't run.
The file that may crash is this Any function may crash but I can't foresee every kind of error. That is why I am looking for a solution to catch an error inside this file.
If you run the code in my repo with node testme.js you will get the following error
results[trackingId] = trackingArray.doesntExist.Something;
^
TypeError: Cannot read property 'Something' of undefined
As you see that catch handler doesn't catch the error.
If apiCall can crash without calling the callback (with an error), I assume it throws some error that can be handled outside it with a try... catch block (although I'm not sure, because I don't know the internal code of apiCall).
You can try the following:
function test1(input) {
return new Promise(function(resolve, reject) {
try {
apiCall(input, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
} catch (e) {
// reject the errors not passed to the callback
reject(e);
}
});
}