Callbacks and error handling in an asynchronous function - javascript

I'm trying to improve my understanding of callbacks/error handling/async structure of Node.js working on challenges at nodeschool.io.
I have one local module file and one actual program file. Here they are:
my_module.js
module.exports = function(path, extension, callback) {
var fs = require('fs');
if (path) {
fs.readdir(path, function(err, list) {
if (err) return callback(err);
var filtered = list.filter(function(item) {
//console.log(item.split("."));
if (item.split(".")[1] == extension) return item
})
callback(null, filtered);
})
} else {
callback("===> Please provide a directory path.")
}
}
program.js
var my_module = require('./my_module');
var path = process.argv[2];
var extension = process.argv[3];
my_module(path, extension, function(err, data) {
if (err) return new Error(err);
console.log(data.join("\n"));
})
This program works just fine. BUT when it should give an error, it doesn't.
Inside my_module.js, if path variable is empty I want to give the error "Please provide a directory path.". The weird thing is, when I write console.log instread of callback, I can show the message. But when I call the callback as callback("===> Please provide a directory path.") nothing happens. No errors, it's silent.
Why is this? And how to fix that?
Thanks

It is silent because in your program.js, you are not consuming the error.
Think program.js is going to consume your module. module.js doesn't know what to do with error. it just passes the err and data to your program.js which consumes it. So its the responsibility of program.js to do whatever it wants to with the error. Something like log it on console, etc.
Try this:
my_module(path, extension, function(err, data) {
if (err) return console.log(err);
console.log(data.join("\n"));
})

You may want to throw that error rather than return it, depending on the error handling pattern for your application.
var my_module = require('./my_module');
var path = process.argv[2];
var extension = process.argv[3];
my_module(path, extension, function(err, data) {
if (err) throw new Error(err);
console.log(data.join("\n"));
})
As a recommendation, since process.arg[] contains user-specified input, I'd actually recommend doing the parameter checking with user-friendly (pretty) error messages (rather than an exception) BEFORE calling my_module(). my_module() itself can then be modified to check and throw an exception if any bogus parameters are passed in.

Related

NeDB not loading or storing to file

I cannot get the simplest example of NeDB to run properly. My code only works in-memory, persistence to file keeps failing without any error messages.
The error callbacks for the loaddatabase and insert events always pass a null reference as error, so no information there. Oddly it seems no one else has this issue, so I guess I'm missing something here. All help is much appreciated.
Here is the code:
var Datastore = require('nedb'), db = new Datastore({ filename: 'test.db' });
db.loadDatabase(function (err) {
alert(err); // err is null, with the autoload flag no error is thrown either
});
var doc = { hello: 'world'};
db.insert(doc, function (err, newDoc) {
alert(err); // err is null here as well. Doc will be in the memory storage but no persisted to file
});
Although this question is pretty old, I'd like to share my experience for anyone facing a similar issue.
NeDB API does not allow JSON input. You have to put in a javascript object. When you use JSON input, no error is returned and nothing will be persisted.
'null' is returned as error in callback to signal that no problem occurred. When saving the first JSON document it is indexed with 'undefined' key, because NeDB calls 'key = obj[fieldname[0]]' which returns 'undefined', when the obj is just a (JSON) string. No error is returned unfortunately. Inserting a second document will cause a unique constraint violation error in the callback as the key 'undefined' has already been taken. Anyhow, nothing will be persisted.
Try
var Datastore = require('nedb'), db = new Datastore({ filename: 'test.db' });
db.loadDatabase(function (error) {
if (error) {
console.log('FATAL: local database could not be loaded. Caused by: ' + error);
throw error;
}
console.log('INFO: local database loaded successfully.');
});
// creating the object with new, just to make it clear.
// var doc = {hello: 'world'}; should work too.
function myDoc(greeting)
{
this.hello=greeting;
}
var doc = new myDoc('world');
db.insert(doc, function (error, newDoc) {
if (error) {
console.log('ERROR: saving document: ' + JSON.stringify(doc) + '. Caused by: ' + error);
throw error;
}
console.log('INFO: successfully saved document: ' + JSON.stringify(newDoc));
});
Maybe it helps someone. :)
This question is quite old but since I had very similar problem I thought that I'll write my resolution for anyone facing similar issues.
In my case I was writing Electron app using electron-webpack as an application builder. It turns out that NeDB loaded by Webpack was running in browser mode without access to file system.
To get it working I had to change import statement from:
import DataStore from 'nedb';
to this:
const DataStore = require('nedb');
Also I had to add NeDB to Webpack configuration as external module (in package.json):
"electronWebpack": {
"externals": {
"nedb": "commonjs nedb"
}
}
I have found this resolution on NeDB github page: https://github.com/louischatriot/nedb/issues/329
All I had to do to fix this was delete the .db file and let the program make one for me by running it one more time.
The other thing I did that could have fixed it was making sure my package.json had all the required information. this can be easily done with a quick "npm init" in the terminal.

Blocking Node in Script

I'm using Node.js to write system scripts that run on a server. Due to Node's asynchronous nature, my script is exiting before the database calls have a chance to complete and nothing is ever written to the database.
I'm using Mongoose as an ORM and talking to a MongoDB, if that makes any difference. Node.js offers SYNCHRONOUS method calls for this very reason, for example: https://nodejs.org/api/child_process.html
I guess my questions are:
1) Does mongoose offer a way to block so my scripting process can wait for the database call to return?
2) If not, is there another method I should consider other than something like:
(function wait () {
if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000);
})();
3) Is node not the best tool for the job for writing scripts? I love node for web app development, and can write nested callbacks or work with promises all day long. But what about as a scripting language?
EDIT -----------------------------------------------
Below is an quick example of the script to provide more clarity of the situation:
#!/usr/bin/env node
# Please note the above that this is a bash script
var schema = mongoose.Schema({
// ... attributes ...
});
var model = new (mongoose.model('ModelObject'))();
model['attribute'] = 42;
console.log('This gets printed first');
model.save(function(err) {
console.log('Nothing in the callback gets printed because callback is never called');
if(err) { // Can't check for errors because this is never reached
console.log('This never gets printed to the screen');
console.log('And consequently nothing is ever saved to mongo');
} else {
console.log('This never gets printed either');
}
});
console.log('This gets printed second');
If your model does not get saved, there is a Mongo error. Following MongoDB conventions you have to check for errors:
model.save(function(error, savedItem) {
if(error) {
// nothing is saved
}
});
Otherwise, have you considered using Promises? It useful for chaining events and simpler error handling.
Promise = require('bluebird');
Promise.promisifyAll(mongoose.Query.base);
model.saveAsync().then(function(savedItem) {
// saved
})
.catch(function(error) {
// handle error
});
I think you are looking for this, check below if this help you.
var mongoose = require('mongoose'),
model1 = mongoose.model('model1'),
model2 = mongoose.model('model2');
model1.findOne({"type" : 'Active'}, function err(err, catConfig) {
if(!err.error){
//This will execute once above DB call is done!
model2.findOne(condition).remove(function(err, gAnalysis) {
//Lines of code that you want to execute after second DB call
});
}
});
I don't see you opening a connection to the database so presumably saving a model instance does nothing, not even call the callback with an error...
I've tested the below example:
test.js:
var mongoose = require('mongoose');
var kittySchema = mongoose.Schema({
name: String
});
var Kitten = mongoose.model('Kitten', kittySchema);
mongoose.connect('mongodb://localhost:27017/test', function (err) {
if (err) throw err;
var silence = new Kitten({ name: 'Silence' });
silence.save(function (err, saved) {
if (err) throw err;
console.log('Kitty Silence is saved!');
mongoose.disconnect(function (err) {
if (err) throw err;
console.log('done...');
});
});
});
Running node test.js prints this to the console:
Kitty Silence is saved!
done...
and examining my local test database shows that Silence is indeed saved.

Files is deleting before its used in node js

I'm new to node js and i'm trying to do the following:
function createPasswordfile(content)
{
fs.writeFile(passwordFileName,content, function(err) {
if(err) {
console.log("Failed on creating the file " + err)
}
});
fs.chmodSync(passwordFileName, '400');
}
function deletePasswordFile()
{
fs.chmodSync(passwordFileName, '777');
fs.unlink(passwordFileName,function (err) {
if (err) throw err;
console.log('successfully deleted');
});
}
and there are three statements which call these functions:
createPasswordfile(password)
someOtherFunction() //which needs the created password file
deletePasswordFile()
The problem I'm facing is when I add the deletePasswordFile() method call, I get error like this:
Failed on creating the file Error: EACCES, open 'password.txt'
successfully deleted
Since its non blocking, I guess the deletePasswordFile function deletes the file before other function make use of it.
If deletePasswordFile is commented out, things are working fine.
How should I prevent this?
writeFile is asynchronous, so it's possible the file is still being written when you try and delete it.
Try changing to writeFileSync.
fs.writeFileSync(passwordFileName, content);

understanding node.js callback

I'm using urllib to make a request to a webpage and I'm trying to return it's headers like so:
var getHeaders = function(webpage){
var info = urllib.request(webpage, {}, function(err, data, res){
// console.log(res.headers); works fine and shows them
return res.headers; // I thought it should make the info variable have the headers information
});
return info;
}
Now when I try to get the headers like maybe set-cookie of a webpage I intended it to return the that from the website but it doesn't, so is there a way to return the headers or is it just not possible to do that?
In Node pretty much everything is done asynchronously, so you'll just need your function to be asynchronous.
var getHeaders = function (webpage, done) {
urllib.request(webpage, {}, function(err, data, res){
done(err, res.headers);
});
}
The traditional pattern is to use callbacks that return an error as the first argument (or a falsy value in case everything went well), and whatever you need to return afterwards.
Consuming the method is then very similar to what you had to do with the urllib thing.
getHeaders(webpage, function (err, headers) {
if (err) {
throw err; // or, you know, deal with it.
}
console.log(headers);
});

Node xml2js is returning 'undefined' when using parseString()

I'm using this package elsewhere and it's working just fine, however in one particular example with one XML file I'm getting "undefined" errors.
Example:
fs.readFile('./XML/theXMLfile13mb.xml', 'ascii', function(err,data){
if(err) {
console.log("Could not open file " + err);
process.exit(1);
}
parseString(data, function (err, result) {
console.log(result); // Returns undefined
var json1 = JSON.stringify(result); // Gives an error
var json = JSON.parse(json1);
The xml2js docs don't really mention how this might be possible/what this might mean. I've tried using other XML files and they work fine. This particular XML file is no bigger than the others nor does it appear to be any less in-tact (it opens fine in my browser and all the data is presented as expected).
Any ideas on how I could troubleshoot this?
You need to convert the data from a Buffer to a String, use this:
parseString(data.toString(), function (err, result) {
Instead of:
parseString(data, function (err, result) {

Categories

Resources