What's the best way to pass thisArg to a require()d module?
I want to do something like this:
index.js
function Main(arg) {
return {
auth: auth,
module: require('/some/module')
}
}
module.js
module.exports = {
someMethod: function() {...}
}
Then, in my code somewhere I call Main(), which returns the object.
So Main().auth exists, cool. But how do I access it from Main().module?
The thisArg in Main().module.someMethod() points to the module itself.. but I need the parent.
Is there any way to do this without using new keyword, functions and prototypes?
EDIT:
Thanks for all the answers guys! Some additional info:
Main() is the module what I wanna require() and use in my app. The "module" Main tries to import is actually just sub functionality of Main, it's just a part of code which I moved to a separate "module" to better organize the code.
So a better example would be:
function RestApi(param) {
return {
common_param: param,
commonFunc: function() {...}
endpoint1: require('/some/module'),
endpoint2: require('/some/module2'),
endpoint3: require('/some/module3')
}
}
And my app would use it like this:
RestApi = require('./RestApi')
RestApi().endpoint1.someHTTPCall(...)
But inside someHTTPCall(), both "common_param" and "commonFunc" should be accessible via thisArg, like this.commonFunc().
So this is kinda a general question, how do you merge multiple modules using require() properly, so "this" would point to the right object (i.e.: the parent)
I know this could be achieved using Function.prototype and inheritance, just would like to know if there is a simpler way.
The best I found so far is something like this:
var _ = require('lodash');
function Module(auth) {
this.auth = auth || {};
}
Module.prototype = {
endpoint1: function() { return _.extend(require('./endpoint1'),{auth: this.auth, commonFunc: commonFunc})}
}
function commonFunc() {...}
However, this is not ideal, since RestApi.endpoint1() would create a new the object on every call.
Is there a better way to handle this?
Thanks in advance!
Create own "require" module with auth param and allways use it.
project/module/require2.js
module.exports = function(path, auth){
if (!check(auth))
return null
return require(path)
}
You could change the module to return a function, like this:
// some/module.js
module.exports = function(mainModule) {
var main = mainModule;
return {
someMethod: function() {
main.doSomethingElse();
}
}
}
Then require it passing the main object:
function Main(arg) {
var main = {
auth: auth,
other: stuff,
};
main.module = require('/some/module')(main);
return main;
}
Related
I have a situation. I use Node.js to connect to a special hardware. let assume that I have two functions to access the hardware.
hardware.send('command');
hardware.on('responce', callback);
At first, I made a class to interface this to the application layer like this (I write simplified code over here for better understanding)
class AccessHardware {
constructor() {
}
updateData(callback) {
hardware.on('responce', callback);
hardware.send('command');
}
}
Now, the problem is that if there are multiple requests from the application layer to this access layer, they should not send multiple 'command' to the hardware. Instead, they should send one command and all of those callbacks can be served once the hardware answer the command.
So I update the code something like this:
class AccessHardware {
constructor() {
this.callbackList = [];
hardware.on('responce', (value) => {
while (this.callbackList.length > 0) {
this.callbackList.pop()(value);
}
});
}
updateData(callback) {
if (this.callbackList.length == 0) {
hardware.send('command');
}
this.callbackList.push(callback);
}
}
Of course, I prefer to use promise to handle the situation. so what is your suggestion to write this code with promise?
Next question, is this approach to make a 'list of callbacks' good?
I prefer to use promise to handle the situation. So what is your suggestion to write this code with promise?
You'd store a promise in your instance that will be shared between all method callers that want to share the same result:
class AccessHardware {
constructor(hardware) {
this.hardware = hardware;
this.responsePromise = null;
}
updateData() {
if (!this.responsePromise) {
this.responsePromise = new Promise(resolve => {
this.hardware.on('responce', resolve);
this.hardware.send('command');
});
this.responsePromise.finally(() => {
this.responsePromise = null; // clear cache as soon as command is done
});
}
return this.responsePromise;
}
}
Btw, if hardware is a global variable, there's no reason to use a class here.
Is the current solution to make a 'list of callbacks' good?
Yes, that's fine as well for a non-promise approach.
I'm new to nodejs and trying to learn the basics by rebuilding an existing i2c sensor system.
Got it all running using a named functions and async.series inside a single file. To keep make reusable i now want to create a class which i then can import. unfortunatly i get some errors i don't understand.
class.js
const async = require('async');
const i2c = require('i2c-bus');
class Sensor {
constructor (channel) {
this.channel = channel;
var self = this;
}
openBus (callback) {
bus = i2c.open(self.channel, (err) => {callback()}); // shorted for stackoverflow
}
closeBus (callback) {
bus.close( (err) => {callback()}); //also shorted for better readability
}
connection (callback) {
/* first variation */
async.series([openBus, closeBus], callback);
connection2 (callback) {
/* second variation */
async.series([this.openBus, this.closeBus], callback);
}
}
module.exports = K30;
when i import the class, i can without any problem create a new sensor 'object' and call the functions directly using:
> var Sensor = require('./class.js');
> var mySensor = new Sensor(1);
> mySensor.openBus(foo);
> mySensor.closeBus(bar);
but if i go an try call the wrapper-functions, i get the following errors:
> mySensor.connection(foo);
ReferenceError: openBus is not defined (at 'connection')
> mySensor.connection2(foo);
ReferenceError: self is not defined (at 'openBus')
i believe those errors occure due to my lack of understanding the correct usage of this and self. sadly i can't find any good ead on that topic. any help is highly appreciated.
UPDATE
the solution provided in the first two anwsers was in fact my first approch before starting to use "self" (after some googling [this-that-trick]).
anyways, here is the output/error i get using "this.channel" instead:
> mySensor.connection2(foo);
TypeError: Cannot read property 'channel' of undefined (at openBus)
This is not saved anywhere var self = this; and therefore is lost when the function (constructor is function) ends.
Just remove the above line in constructor and use everywhere the this instead of self.
Its true that this keyword is little tricky in javascript, but if you follow reasonable approach, you should be fine.
You indeed have issue with this and self
Every member inside the class has to be referred by this. If you declare a variable named var EBZ-Krisemendt = "SO user";, to access it, you need to use it with this, eg: console.log(this.EBZ-Krisemendt);
What you need here is
openBus (callback) {
bus = i2c.open(this.channel, (err) => {callback()});
}
and then mysensor.connection2(foo) will work fine.
while i still don't fully understand the reason behind this i fixed my code by getting rid of that "ES6" class definition.
class.js
const i2c = require('i2c-bus');
const async = require('async');
function Sensor(channel) {
let that = this; // make 'this' available in sub-function scope
this.channel = channel;
function openBus(cb) {
// open the bus-connection
bus = i2c.open(that.channel);
}
function closeBus(cb) {
// close the bus-connection
}
function connection(cb) {
async.series([openBus, closeBus], cb);
}
function getReading(cb) {
async.until(
function() {
// loop condition e.g. max tries to get reading
},
function(cb) {
connection(cb); // calling nested synchronous connection-routine
},
function (err) {
// result handling
}
); // end async.until
} // end getReading
return {
getReading: getReading
} // make only 'getReading' available
}
module.exports = {
Sensor: Sensor
} // make 'Sensor' available
in the 'member'-functions i can now use the 'class'-variables of 'Sensor' by accessing them with 'that' (e.g.: 'that.channel')
Detail:
function openBus(cb){
bus = i2c.open(that.channel);
}
if i'd use this instead of that it would only work while calling openBus directly. in my example it's neccessary to call openBus and closeBus in a synchronous manner (for obvious reasons). since async.series is additionally nested inside async.until (sensor might need several tries to response) the scope of this changes. by using that instead i'm able to ignore the scope.
Comment:
since the solution is kinda generally pointing to using nested async-calls inside custom modules i'll slightly alter the titel of the initial question. i'm still hoping for better solutions and/or explanations, so i won't mark my own anwser as accepted yet.
I have this in my .js file:
exports.generate = function(details) {
// bunch of code
// returns Promise
}
exports.save = function(details){
exports.generate(details)
.then(function(id){
//save in db
})
}
Is it okay to use an exported function like this? Or is there a better way..?
It depends on if you want consumers of the module to be able to influence the module's behavior by overwriting exports.generate (e.g. require('foo').generate = function() {...}).
If you don't want users to be able to influence it in this way, then your best bet is going to be pulling out the generate() function and naming it, then exporting that and using the function directly by name inside save():
function generate(details) {
// ...
}
exports.generate = generate;
exports.save = function(details) {
generate(details).then(function(id) {
// ...
});
};
Otherwise if you do want to allow users to override the generate() functionality, then what you are currently doing is fine.
var _this=this;
exports.save = function(details) {
_this.generate(details) ...
};
In Meteor (a NodeJS Framework), there is a function called Meteor.userId() that always returns the userId that belongs to the current session as long as I am in a function that was original called from a Meteor Method.
The Meteor.userId() function utilizes meteors DDP?._CurrentInvocation?.get()?.connection. So somehow this "Magic line" gets my current DDP connection. This also works when burried deep inside of callbacks.
So somehow meteor sets a context that it refers to. I also want to do this kind of trick for another API that doesn't utilize meteors DDP but is a plain HTTP Api.
What I want to do:
doActualStuff = function(param1, param2, param3) {
// here, i am burried deep inside of calls to functions
// but the function at the top of the stack trace was
// `answerRequest`.
// I want to access its `context` here but without
// passing it through all the function calls.
// What I want is something like this:
context = Framework.getRequestContext()
}
answerRequest = function(context) {
//do some stuff
someFancyFunctionWithCallback(someArray, function(arrayPosition) {
aFuncCallingDoActualStuff(arrayPosition);
})
}
I can wrap the call to answerRequest if this is necessary.
I don't know how Meteor does it, but it doesn't look like magic. It looks like Meteor is a global object (window.Meteor in the browser or global.Meteor in Node.js) that has some functions that refer to some stateful object that exists in the context where they were defined.
Your example could be achieved by having answerRequest (or whatever function calls answerRequest, or whatever you want) call a setRequestContext function that sets the state that will be returned by getRequestContext. If you wanted, you could have an additional function, clearRequestContext, that cleans up after request is over. (Of course, if you have async code you'll need to take care that the latter isn't called until any code that needs that data has finished running.)
This is rudimentary, but it might look something like the below snippet. window.Framework does not need to be defined in the same file as the rest of the code; it just needs to be initialized before answerRequest is called.
let _requestContext = null;
window.Framework = {
setRequestContext(obj) {
_requestContext = obj;
},
getRequestContext() {
return _requestContext;
},
clearRequestContext() {
_requestContext = null;
},
};
const doActualStuff = function(param1, param2, param3) {
const context = Framework.getRequestContext()
console.log('Request context is', context);
}
const answerRequest = function(context) {
Framework.setRequestContext(context);
setTimeout(() => {
try {
doActualStuff();
} finally {
Framework.clearRequestContext();
}
}, 100);
}
answerRequest({ hello: 'context' });
.as-console-wrapper{min-height:100%}
Ive node moudle which i need to export two functions and get to both of the function a parameter arg1,I try with the following I got error,what am I doing wrong here ?
UPDATE
Ive two method inside module
1. I need to expose it outside and to call it explicit from other
module with parameter
like
require('./controller/module')(functionName1)(parameter);
another function(functionName2) in this module which I need to call it explicit with two parameter ,how should I do it right?
It is not very clear what you want to do, but i think you want something like that:
module.exports = function (arg1) {
return {
server: function (params1) {
//do something with arg1 and params1
},
proc: function (params2) {
//do something with arg1 and params2
}
}
};
And using the module:
var arg1 = 'whatever'
var myMod = require('myMod')(arg1);
myMod.server();
myMod.proc();
Option 2
If i look at your new example
require('./controller/module')(functionName1)(parameter);
you need module that exports a function that returns another function (Higher Order Function).
So for example:
module.exports = function(functionName1) {
if(functionName1 === 'server'){
return function server(parameter){
//do your stuff here
}
}
if(functionName1 === 'proc'){
return function proc(parameter){
//do your stuff here
}
}
};