How to pass context or attributes in async.js waterfall? - javascript

I would like to pass the current context or an attribute to functions in async.waterfall. How to:
pass this
an attribute (here options object)
This is what I already have:
var _authenticate = function (cbAsync) {
var licenseId = options.licenseId; //options is undefined
};
module.exports = new Command('createOrga')
.description('creates an organization')
.option('-f, --file <file>', 'the structure file including full path')
.action(function (options) {
options.confirm = options.confirm || true; // No confirmation needed!
options.organizationUUID = (uuid.v4()).toUpperCase();
options.licenseId = (uuid.v4()).toUpperCase();
//How to pass options object to _authenticate function????
async.waterfall([ _authenticate ], function(err) {
if ( err ) {
console.warn('Error in creating new organization: ',err);
}
else {
console.info('Successfully created new organization: ' + organizationUUID);
}
});
}
}

You could use Function.prototype.bind() to pass variables.
async.waterfall([ _authenticate.bind(undefined, options)], function(err) {
//your code
});
Because the bound variables are pass first, your callback then has to look like this:
var _authenticate = function (options, cbAsync) {
var licenseId = options.licenseId; //options is undefined
};

Related

JavaScript - var self = this; self is undefined [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
so here is a situation that i have. I have a constructor function with many properties and methods. here are the properties:
var Brain = function(){
this.util = require('util');
this.fs = require('fs');
this.assert = require('assert');
this.Sequelize = require('sequelize');
this.JsonField = require('sequelize-json');
this.bcrypt = require('bcrypt-nodejs');
this.bodyParser = require('body-parser');
this.fileUpload = require('express-fileupload');
// Custom Modules
this.ModelsModule = require('./models');
this.TombModule = require('./tomb');
}
a few of the methods are defined to call a given callback and pass data to it, for example:
Brain.prototype.db_read = function(request, response, data, callback) {
var self = this;
self.ModelsModule[data.Model].findOne(data.where)
.then(function(obj) {
// console.log(obj);
callback(request, response, obj);
})
.catch(function(error){
console.log(error);
});
}
Here is the thing - the callback function is always going to be another method of the same constructor function. here is another method that would be a callback:
Brain.prototype.login = function(request, response, user) {
var self = this;
// console.log('form-data --- ', request.body);
if(user == null || user == undefined) {
console.log('Account Load: Failed');
return response.render( self.TombModule.pages['login'], {error: 'Invalid Credentials'} );
}
else {
// console.log(user.dataValues);
if( self.bcrypt.compareSync(request.body.pswrd, user.dataValues.pswrd) == false ) {
console.log('Account Load: Failed');
return response.render( self.TombModule.pages['login'], {error: 'Invalid Credentials'} );
}
console.log('Account Load: Successful');
request.session.you = {
id: user.dataValues.id,
f_name: user.dataValues.f_name,
m_initial: user.dataValues.m_initial,
l_name: user.dataValues.l_name,
icon: user.dataValues.icon,
background: user.dataValues.background,
email: user.dataValues.email,
phone: user.dataValues.phone,
fax: user.dataValues.fax,
uv: user.dataValues.uniqueValue
};
return response.redirect('/home');
}
}
In my app.js a new instance of Brain is created.
const RoutinesModule = require('./routines');
const brain = new RoutinesModule.Brain();
The Entire chain of events starts from an express POST route:
app.post('/login', function(request, response){
var data = {
Model: 'Users',
where: {where: {email: request.body.email}}
}
brain.db_read(request, response, data, brain.login);
});
Notice that the callback, the last parameter, for Brain.db_read is Brain.login, which is another method of the same constructor. here is where the problem is happening.
When POST requests to /login hits the app.js, it's going to query the database and give the results to any given function to handle it, in this case Brain.login
inside of Brain.db_read(), var self = this; works. it points to itself, the instance of the Brain. however, when it calls the callback which is Brain.login, the statement inside of Brain.login, var self = this; does not work. it results in undefined, causing an error.
Why is that happening? why is var self = this; inside of the Brain.login resulting in undefined?
Ultimately what i am trying to do is create a set of main functions to handle database operations(CRUD) instead of doing database operations inside of each individual function, which is/could be an indefinite amount.
I could easily just require that module in that function definition but i would strongly prefer to access its property for dynamic, scalable, and efficiency means.
Thanks!
You're passing the method, brain.login, as a function that has no owner. You're just passing the function reference. You need to do brain.login.bind(brain).

Property cannot be read after wrapping function

var sync = Meteor.wrapAsync(connection.query);
var rows = sync(selectMailgunChecked);
var emails = rows.map(function(a) {
return a.email
});
var from = 'sample#email.com';
emails.forEach(function(entry) {
mailgunSend( entry, from, contentHTML, contentRAW, subject, tags);
});
Code above (wrapped function of connection.query from node-mysql use in Meteor app) gives me an arror:
Cannot read property 'typeCast' of undefined
It is somehow related to sync(selectMailgunChecked) and external library (from node-mysql) Connection.js:
Connection.prototype.query = function query(sql, values, cb) {
var query = Connection.createQuery(sql, values, cb);
query._connection = this;
if (!(typeof sql == 'object' && 'typeCast' in sql)) {
query.typeCast = this.config.typeCast;
}
if (query.sql) {
query.sql = this.format(query.sql, query.values);
}
this._implyConnect();
return this._protocol._enqueue(query);
};
Every variable in my code is defined and sucessfully passed. What Can be wrong here?
this.config in this line
query.typeCast = this.config.typeCast;
is undefined.
You have to define the context (this) in which the wrap async function connection.query is executed by passing it as the second parameter
var sync = Meteor.wrapAsync(connection.query, connection);

Stub a Function with Callback

Normally I use this code:
aws_stub.S3 = function(){};
var fake_aws_listObjects = function(params, func){func("failure", null)};
var fake_aws_listObjects_stub = sinon.spy(fake_aws_listObjects);
aws_stub.S3.prototype.listObjects = fake_aws_listObjects_stub;
To stub a function like the following one:
new AWS.S3().listObjects(that.build_params(), function(err, data) {
if(err){
that.make_failure_callback();
}
else{
that.add_keys(data);
if(data.IsTruncated){
that.make_request(data.NextMarker);
}else{
that.make_success_callback(that.keys);
}
}
});
The problem with this stubbing is that on each request it returns the same
Now I wanted to do is different stubbing for each call:
aws_stub.S3 = function(){};
var fake_aws_truncated = function(params, func){func(null, {
Contents: [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/1:::2.jpg"}],
IsTruncated: true,
NextMarker: "nextMarker"
})};
var fake_aws_listObjects = function(params, func){func(null, {Contents: [{
Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/2:::3.jpg"
}]})};
var fake_aws_listObjects_stub = sinon.stub();
fake_aws_listObjects_stub.onCall(0).returns(fake_aws_truncated);
fake_aws_listObjects_stub.onCall(1).returns(fake_aws_listObjects);
aws_stub.S3.prototype.listObjects = fake_aws_listObjects_stub;
The problem seems to be returns, it doesn't execute the function!!
I also cannot write it like this:
fake_aws_listObjects_stub.onCall(0) = fake_aws_truncated;
Because this would be a wrong hand assignment!
What do I have to change? Here are the sinon docs: http://sinonjs.org/docs/
Thanks!!
I would probably go about it another way.
If you want to stub AWS.S3.prototype.listObjects, I would do that like so:
var stub = sinon.stub(AWS.S3.prototype, 'listObjects');
To call the callback with various values, use stub.yields():
stub.onCall(0).yields(null, {
Contents : [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/1:::2.jpg"}],
IsTruncated : true,
NextMarker : "nextMarker"
});
stub.onCall(1).yields(null, {
Contents : [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/2:::3.jpg"}]
});
To test your code, you just call listObjects like before:
var s3 = new AWS.S3();
s3.listObjects(params, function(err, value) {
...`value` is now one of the fixtures you declared above...
});
To restore to the original version of the method, use one of these:
stub.restore();
// OR:
AWS.S3.prototype.listObjects.restore();

Async Recursion with JavaScript and Node.js

This is probably a noob JavaScript question, but I'm looking to know if my solution to a problem I am having is 'correct'
I have created the following sample application that recreates my error:
Firstly in index.js
var processor = require('./fileProcessor/processor.js');
var container = {
source: "source.txt",
destination: "destination.txt"
};
new processor().process(container);
I create my container object which has the name of the source file and the name of the destination file. This is passed into the process function of the processor:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
this.process = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, this.process);
} else {
file.write(container, this.process);
}
}
};
};
As you can see this calls the read and write functions passing in the container and the process function as the callback, the fileProcessor looks like this:
var fs = require('fs');
module.exports = function() {
this.read = function(container, callback) {
fs.readFile(container.source, function (err, data) {
if(err) throw err;
container.body = data;
callback(container);
});
};
this.write = function(container, callback) {
fs.writeFile(container.destination, container.body, function(err) {
if(err) {
return console.log(err);
}
container.finished = true;
callback(container);
});
};
};
In simple terms the processor calls file.read, which reads the file and calls back into the process function, which then calls the write function. However at the end of the write function an error is thrown:
callback(container);
^
TypeError: object is not a function
Obviously when passing in this.process to file.write(container, this.process); the this isn't the this I intend it to be!
If I update my processor by adding a processFunction variable:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
var processFunction = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
this.process = function(container) {
processFunction(container);
};
};
Everything works fine. Is this a good way to do this or is there a better solution?
I think this is a fine way to do it. There is one possible modification that you might make. Since you are creating a new name in your scope just for the purpose of recursing, you could just name your function and refer to it by its name inside of the function.
module.exports = function Processor() {
this.process = function processFunction(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
};
Then you can avoid creating a name (processFunction) that will be visible outside the function.
Take a look here for reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression

Issue with prototype inheritance in Javascript (Node.js)

I have two files: BaseController.js and EventRecordController.js. EventRecord needs to inherit a few methods from BaseController.
BaseController
var Q = require('q'),
util = require('../util');
exports.BaseController = function(req, res) {
this.req = res;
this.res = res;
this.fields = {};
this.error = {
code: 200,
message: 'BAD REQUEST: The parameters provided were invalid. See response body for error messages.',
specific_message: ''
};
};
// Utility method to handle returning errors that are thrown.
exports.BaseController.prototype.handle_errors = function(error) {
if(this.error.code === 500) {
util.internal_error(this.res, this.response_type);
} else {
var response = util.build_error_response(this.response_type, this.error.code, this.error.message, this.error.specific_message);
util.send_response(this.res, this.response_type, this.error.code, response);
}
};
// Check to see if a user is authenticated and whether they are using a correct response type.
exports.BaseController.prototype.validate_response_type_and_authenticate = function() {
var deferred = Q.defer();
util.validate_response_type_and_authenticate(this.req, this.res, function(auth_data, response_type) {
this.auth_data = auth_data;
this.company_user_uid = this.auth_data.data.company.uid;
this.response_type = response_type;
this.v3_token = this.auth_data.data.token;
deferred.resolve();
});
return deferred.promise;
};
EventRecordController
var base_controller = require("./BaseController"),
Q = require('q'),
util = require('../util'),
validator = require('validator');
exports.EventRecordController = function(req, res) {
function EventRecord(req, res) {
base_controller.BaseController.apply(this, arguments);
}
// Inherit from BaseController, then fix constructor.
EventRecord.prototype = new base_controller.BaseController();
EventRecord.prototype.constructor = EventRecord;
EventRecord.run = function() {
console.log(this.error);
};
return EventRecord;
};
When I run the following code, this.error logs as undefined from within the run() method.
var event_record_controller = require("./controllers/EventRecordController"),
util = require('./util'),
validator = require('validator');
exports.record = function(req, res) {
var controller = new event_record_controller.EventRecordController(req, res);
controller.run();
};
I think I'm missing something obvious here, but my experience with prototype based inheritance is limited.
this.error is undefined because run is being called directly on the constructor, which doesn't have an error, rather than one of its instances.
Methods that are attached directly to the constructor aren't inherited. For that, they should be attached to the prototype:
// "static" method available only through the constructor itself
EventRecord.run = function() {
console.log(this.error);
};
// "class" method inherited by instances of `EventRecord`
EventRecord.prototype.run = function () {
console.log(this.error);
};
But, you also don't yet have an instance of EventRecord to call .run() on.
When a constructor returns an object, the instance that was created by using new will be discarded. So, calling new EventRecordController() is just returning the function EventRecord.
var controller = new event_record_controller.EventRecordController(req, res);
console.log(typeof controller); // function
console.log(controller.name); // "EventRecord"
controller = new controller(req, res);
console.log(typeof controller); // object
You could revise EventRecordController to return an instance of EventRecord:
// ...
return new EventRecord(req, res);
Though, you might consider consolidating the 2 constructors rather than having one generate the other:
exports.EventRecordController = function(req, res) {
base_controller.BaseController.apply(this, arguments);
};
util.inherits(exports.EventRecordController, base_controller.BaseController);
exports.EventRecordController.prototype.run = function () {
console.log(this.error);
};

Categories