what is the best method to multi request with callback or promise on node.js - node.js

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.

Related

nodejs referenceerror on nested function calls using async.series and async.until

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.

Node js. How to share an array between two functions? Is there any less complicated way

I am very new to nodejs and stuck at a place where one function populates an array and the other reads from it.
Is there any simple construct to synchronize this.
Code looks something like Below
let arr = [];
let prod = function() {
arr.push('test');
};
let consume = function() {
process(arr.pop());
};
I did find some complicated ways to do it :(
Thanks alot for any help... ☺️
By synchronizing you probably mean that push on one side of your application should trigger pop on the other. That can be achieved with not-so-trivial event-driven approach, using the NodeJS Events module.
However, in simple case you could try another approach with intermediary object that does the encapsulation of array operations and utilizes the provided callbacks to achieve observable behavior.
// Using the Modular pattern to make some processor
// which has 2 public methods and private array storage
const processor = () => {
const storage = [];
// Consume takes value and another function
// that is the passed to the produce method
const consume = (value, cb) => {
if (value) {
storage.push(value);
produce(cb);
}
};
// Pops the value from storage and
// passes it to a callback function
const produce = (cb) => {
cb(storage.pop());
};
return { consume, produce };
};
// Usage
processor().consume(13, (value) => {
console.log(value);
});
This is really a noop example, but I think that this should create a basic understanding how to build "synchronization" mechanism you've mentioned, using observer behavior and essential JavaScript callbacks.
You can use callback to share data between two functions
function prod(array) {
array.push('test1')
}
function consume() {
prod(function (array) {
console.log(array)
})
}

How to pass this to require() in NodeJS?

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;
}

RequireJS module for SignalR

Rather than copy and pasting my code onto here, I have uploaded it to github. The RequireJS module does have a dependency on jquery.signalr and in tern has a dependency on jquery but also have a dependency on the javascript held in /signalr/hubs. There is a bit of config to do with Require.Config.
Basically what is happening is on the first time you load the page the connection is made to the hubs within signalr and the "server side" code is executed and does the desired thing. When you refresh the page it does not. All client side code is called, so for example:
var myViewModel = new MyViewMode();
myViewModel.init();
and within your init method you have
var connection = $.connection.myHub;
this.init = function() {
connection.server.myMethod();
}
this would then go off to
public MyHub : Hub
{
public void MyMethod()
{
Client.Request.populateSomeInformation() // I think it's request but I'm doing this from memory!
}
}
and then call
connection.client.populateSomeInformation = function () { .. )
but doesn't call this :(
It looks like a connection has been made (using the good old console.log() to see what it outputs) and indeed debugging the project it executes the code within the hub but there is no response made back to the javascript.
So wonderful people of the internet, where am I going wrong? Do I need to check the state of $.connection.hub.start(); before attempting to start it again?
Time for beer :)
I believe it should be
connection.client.populateSomeInformation = function () { .. )
(not connection.server)
http://www.asp.net/signalr/overview/hubs-api/hubs-api-guide-javascript-client#callclient
(observations on the code you have on github right now)
var isLoaded = false;
// ... some code that doesn't change isLoaded ...
if (isLoaded == false) {
scrollIntervalId = window.setInterval(function () {
signalRLoaded();
}, 30);
}
I think isLoaded will always be false at this point. Not sure what you intended this to accomplish.
var connection = $.connection.hub.start();
I don't think you're supposed to open the connection before defining any client functions. I don't see any client functions being defined here, so maybe you're doing that somewhere else? I don't know if it really matters other than if the server attempts to call a client function that hasn't yet been defined...
function SignalRReady(callback) {
if (isLoaded) {
callback(connection);
} else {
readyCalls = callback;
}
return SignalRReady;
}
SignalRReady.version = "1.0.0";
SignalRReady.load = function(name, request, onLoad, config) {
if (config.isBuild) {
onLoad();
} else {
SignalRReady(onLoad);
}
};
return SignalRReady;
I'm confused by this bit of code, probably because I don't see how it's being used. Is this an attempt at a kind of singleton? I see that SignalRReady is the "class" being returned for the module. You're not really returning an object, you're returning a constructor which implies that you're instantiating it in other places, something like
define(['SignalRReady'], function(sigR)
{
var srr = new sigR();
});
But then you have that load function defined that calls the constructor and makes this look all weird. How are you using this?
Anyways, I'm thinking you might be hitting some kind of race condition where the client function may not always be available at the time the server is trying to call it.
(additional comments/code 2013-09-06)
Your connection object is actually a jQuery promise ( http://api.jquery.com/category/deferred-object/ ).
If you're unfamiliar with promises, think of them generically as a queue of callbacks to be executed later. In this case, when connected, all the callbacks will be executed (in the order they were added). If a callback is added after being connected, it will get executed immediately. This is how your code is working now. You add the callback to the .done queue after the connection is made and is executed immediately.
If you insist on creating the connection object yourself, then you do not need to use the stateChanged event. You just add the callback to the .done queue:
define(function()
{
function signalRReady(callback)
{
if (window.connection == undefined) {
window.connection = $.connection.hub.start();
}
window.connection.done(callback);
}
signalRReady.version = "1.0.0";
return signalRReady;
});
However, I believe it's not a good idea to initiate the connection yourself. Because your module isn't a complete wrapper around SignalR such that people would only use your module to do SignalR stuff, you are not guaranteed (and cannot expect) other code will not initiate the connection. Especially if someone is adding your module to an existing codebase.
Your module is simply adding a new event, so keep it simple. Take the callback and execute it yourself when appropriate:
define(function()
{
function signalRReady(callback)
{
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
callback();
}
});
}
signalRReady.version = "1.0.0";
return signalRReady;
});
Nowadays, promises are pretty popular. You might want to implement a promise-based module like:
define(function()
{
var deferred = $.Deferred();
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
// executes all callbacks attached by the "ready" function below
deferred.resolve();
}
});
return {
ready: function(callback)
{
deferred.done(callback);
},
version: "1.0.0"
};
});
If callbacks are attached after the connection has been made, they are executed immediately.
Also, notice this example module's init function returns an object instead of a function. Since RequireJS will pass the same instance around to any module that requires it, state is maintained - we can use local variables instead of global.

How can I use threading in MonoDroid such that it will be cross platform compatible with MonoTocuh

Specifically when doing MonoDroid uses of threads all the documentation I can find recommends calling RunOnUiThread() to call the callback. There is a similar function that can be used on MonoTouch however both of them require a GUI (Activity or whatever its counter part is on IOS). What I would like is to be able to start a thread, pass in a callback and call that callback on the thread that started the thread. For example
ThreadPool.QueueUserWorkItem(state =>
{
//Do Stuff
execute_callback_magically_on_main_thread(() => callback(response));
});
Any ideas? To be clear I would prefer this to not need a handle to the Activity etc.
What if you do something like this? (assuming they have the same signature) I haven't messed with RunOnUiThread, so I don't know it's signature.
public delegate void InvokeOnUIMethod(Action action);
public void CallingMethod()
{
//iOS
MyMethod(InvokeOnMainThread, () => { /* Your callback functionality */ });
//Android
MyMethod(RunOnUiThread, () => { /* Your callback functionality */ });
}
public void MyMethod(InvokeOnUIMethod execute_callback_magically_on_main_thread, Action callback)
{
System.Threading.ThreadPool.QueueUserWorkItem(state =>
{
//Do Stuff
execute_callback_magically_on_main_thread(() => callback(response));
});
}
I hope this helps.
Using the Alpha builds (Hopefully soon to be available as stable) you can use the new Async await idiom.
here is an overview on MSDN:
http://msdn.microsoft.com/en-gb/library/vstudio/hh191443.aspx
and here is a great video series on Channel9:
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Tip-1-Async-void-is-for-top-level-event-handlers-only
I found a solution that works and does not appear to be dependent on either platform.
Task<string> t = new Task<string>(() =>
{
//Do Stuff
return "my results";
});
t.ContinueWith(task =>{
if(callback != null)
callback(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
t.Start();
The important part is the TaskScheduler.FromCurrentSynchronizationContext() which tells the "ContinueWith" to execute on the original thread.

Resources