Cannot call function in the same class - node.js

I defined a class called Plan. Here is the code:
class Plan {
async getPlanText(ctx) {
return await this.getPlanDetails(ctx);
}
async getPlanDetails(ctx) {
return ...
}
}
exports.Plan = Plan;
I get:
this.getPlanDetails is not a function
What I did wrong?
I used the Plan class in this way:
const { Plan } = require('./controllers/plan.controller');
let planController = new Plan();
console.log(planController.getPlanText('my context'));

try this. Basically you need to bind the function to a class while passing so it knows where to get the dependencies from. You can read more here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
const planController = new Plan();
const menu = new TelegraphInlineMenu(planController.getPlanText.bind(planController))

Related

Avoid multiple Class Instances using Singleton

Project: Create a dynamodb package using #aws-sdk v3 (client-dynamodb & lib-dynamodb)
Base class
class DynamoDB {
#client: DynamoDBDocumentClient;
constructor() {
const db_client = new DynamoDBClient();
this.#client = DynamoDBDocumentClient.from(db_client);
}
// class methods are get_item, delelte_item etc..
// snip--
}
Class for a table with useful methods
class NoSqlTable extends DynamoDB {
table_name: string;
constructor(table_name: DynamodbTableName) {
super();
this.table_name = table_name;
}
async get_record<K,R>(key: K, params: GetRecordParams = {}) {
const result = await super.get_item({ TableName: this.table_name, Key: key, ...params });
return result.Item as R;
}
// other methods
}
Finally, a set of functions exposed to users of the npm package/project
export const get_user = async(user_id:string) => {
const table = new NosqlTable("user");
const user = await table.get_record({ key: user_id });
return user;
}
export const get_accounts = async(user_id:string) => {
const table = new NosqlTable("account");
const accounts = await table.query_table({ IndexName: "user_id-account_id-index", ...});
return accounts;
}
Target:
Each class NosqlTable and DynamoDB is to be initiated once only.
Note: Once means: 1 if in a server setting (long-running process) or once per request if in serverless mode
Each class should only be initialized if used.
Issue
With the current settings, each function exposed to users like get_user, and get_accounts will initialize the NosqlTable class every time they are called and in turn, calls the DynamoDB class.
For example, in a single request, get_user is called 10 times, and get_accounts is called 5 times,
10 calls to initialize the NosqlTable class with table_name="user",
5 calls to initialize the NosqlTable class with table_name="account"
15 calls to the DynamoDB class.
Solution
Attempt 1
Use a singleton pattern,
let singleton_dynamodb: Dynamodb;
const connect_dynamodb = (params) => {
if(!singleton_dynamodb) singleton_dynamodb = new DynamoDB(params);
return singleton_dynamodb;
}
/* The updated `NosqlTable` class now does not extend DynamoDB class; instead calls the `connect_dynamodb` function
*/
class NoSqlTable {
table_name: string;
this.dynamodb = DynamoDB;
constructor(table_name: DynamodbTableName) {
this.table_name = table_name;
this.dynamodb = connect_dynamodb();
}
async get_record<K,R>(key: K, params: GetRecordParams = {}) {
const result = await this.dynamodb.get_item({ TableName: this.table_name, Key: key, ...params });
return result.Item as R;
}
}
let singleton_nosql_table: NosqlTable;
const connect_nosql_table = (table_name) => {
if(!singleton_nosql_table) singleton_nosql_table = new NosqlTable(table_name);
return singleton_nosql_table;
}
export const get_user = async(user_id:string) => {
const table = connect_nosql_table ("user");
const user = await table.get_record({ key: user_id });
return user;
}
Now, if get_user is called the first time, it will call connect_nosql_table which sets the singleton_nosql_table variable
any subsequent calls to this function will return the singleton_nosql_table setup earlier.
Similarly, any call to the new NosqlTable(table_name) internally calls connect_dynamodb rather than extending Dynamodb class.
Is this the correct way to do it, and what are the best practices to improve this setup?
The ultimate target is to improve performance based on the assumption that initializing 1 class instance is more performant than initializing 100 class instances.
Note: The pattern will be used for other packages/projects, like AWS SQS, AWS SNS, and HTTP Client class per domain.

How to export object from module.exports?

I need to require a file passing a parameter, for this I used the following syntax:
module.exports = function(bot) {
const menu = new TelegrafInlineMenu(bot);
return menu;
};
the problem's that the code above export the function, I need to return the menu object, is there a way to do this?
I require the script using:
const menu = require('menu')(bot);
problem's that menu is a function not an object
function TelegrafInlineMenu(bot) {
// constructor
if (!(this instanceof TelegrafInlineMenu)) {
return new TelegrafInlineMenu(bot);
}
}
TelegrafInlineMenu.prototype.someFunction = function () {
// etc.
};
module.exports = TelegrafInlineMenu;

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

passing function to a class in nodejs

I have a function that I need to pass to a class I have defined in nodeJs.
The use case scenario is I want to give the implementer of the class the control of what to do with the data received from createCall function. I don't mind if the method becomes a member function of the class. Any help would be appreciated.
//Function to pass. Defined by the person using the class in their project.
var someFunction = function(data){
console.log(data)
}
//And I have a class i.e. the library.
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall(){
var result = new Promise (function(resolve,reject) {
resolve(callApi());
});
//doesn't work. Keeps saying notificationHandler is not a function
result.then(function(resp) {
this.notificationHandler(resp);
}) ;
//I want to pass this resp back to the function I had passed in the
// constructor.
//How do I achieve this.
}
callApi(){ ...somecode... }
}
// The user creates an object of the class like this
var obj = new A("abc#gmail.com", someFunction);
obj.createCall(); // This call should execute the logic inside someFunction after the resp is received.
Arrow functions (if your Node version supports them) are convenient here:
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall() {
var result = new Promise(resolve => {
// we're fine here, `this` is the current A instance
resolve(this.callApi());
});
result.then(resp => {
this.notificationHandler(resp);
});
}
callApi() {
// Some code here...
}
}
Inside arrow functions, this refers to the context that defined such functions, in our case the current instance of A. The old school way (ECMA 5) would be:
createCall() {
// save current instance in a variable for further use
// inside callback functions
var self = this;
var result = new Promise(function(resolve) {
// here `this` is completely irrelevant;
// we need to use `self`
resolve(self.callApi());
});
result.then(function(resp) {
self.notificationHandler(resp);
});
}
Check here for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

Async function does not return control to the main thread (linq expression)

I thought that I got threads in .NET, but when I have added LINQ expression it made me a little confused.
Like I wrote in the topic of this discussion I dont why the thread doesnt return control to the main action of my controller.
I have written what makes me silly in comments, so let me skip to the true example:
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s).Result;
//1-The above code doesnt enter into CONVERT function (I have a breakpoint there)
return oss.ToList();//2- this list enter into COnvertt
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{//3 - Naturally it comes here
await Task.Run(()=>
{
//This task is executed (It is example code, pls do not care, that threads do not have any sense
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
}); //Flow comes here and THIS line does not return control to the main action, why? :)
}
}
public class SomeProduct
{
public string copyOfTheLastOne;
public string valeFromAnUpdateFunction;
}
public class Mother
{
public List<Child> internalField;
}
public class Child
{
public string theLastOne;
}
I have solved this example by adding an "executor", which takes list of the tasks and manage it.
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
List<Task<SomeProduct>> downloadTasks = oss.ToList();
List<SomeProduct> ossNew = new List<SomeProduct>();
while (downloadTasks.Count > 0)
{
var firstFinishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(firstFinishedTask);
ossNew.Add(await firstFinishedTask);
}
return ossNew;
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{
await Task.Run(()=>
{
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
});
}
To fully understand the problem, I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
You're running into a common deadlock problem that I explain in full on my blog, due to the use of Result. Use await instead of Result and your problem goes away (in your case, since you have a collection, you'll want to await Task.WhenAll):
public async Task<SomeProduct[]> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
return Task.WhenAll(oss);
}
On a side note, you shouldn't use Task.Run in your implementations, particularly on ASP.NET. On ASP.NET, Task.Run completely removes all the benefits of async and adds overhead.

Resources