Unable to call javascript function globally - javascript

I am developing nodejs app with mongoDB. I have written a function which will filter some data from mongodb and store in variable "docs". I tried several methods to declare a function globally and tried to access that variable "docs" but I couldn't.`
conn.then(client=> client.db('myprojectone').collection('offlinemessage').find({nameTo:"sd"}).limit(1).toArray(function(err, docs) {
if(err) { console.error(err) }
res.send(JSON.stringify(docs))
console.log(docs);
return docs;
}))
`

Make one helper function which performs all your requirement along with DB query and filter result and returns that result. Exports this function using module.exports like below.
utils.js // Helper file
const utils = {};
utils.getData = async () => {
try {
// ...Your business logic
return true; // It will be your variable
} catch (err) {
logger.error(err);
throw err;
}
};
module.exports = utils;
call utils.getData() to get your result;
userController
const utils = require('./helper/utils');
const userController = {};
userController.getData = async () => {
try {
const result = await utils.getData();
} catch (err) {
logger.error(err);
throw err;
}
};
module.exports = userController;

You can't access async function variable outside of function.

Express.js Gives simple thing to access global functions
fnName = function(){ return "hi"; }; // i.e. don't do: var name = function(){ ... };
console.log(fnName()); // this prints "hi"
console.log(global.fnName()); // this also prints "hi" - it was assigned to global.

One possible solution would be to create a service js class file, called utils.js and then add in this class that you require globally,
utils.js
export default class Example {
static getDocs() {
// Rest of the global method
}
}
And in the place that you require the docs variable, you simply call the method getDocs()
import Utils from '<location_to_utils.js>';
console.log(Utils.getDocs());

Related

Async Await of imported asynchronous function not waiting correctly

I'm flummoxed.
I have created an asynchronous utility function that I am exporting from one file and importing into a React Class Component.The function makes an API call to an authentication service which returns an object.
My goal is to be able to call that function in my component and set the returned object equal to a variable called "tokens" which I can then further manipulate.
My problem is that no matter how I seem to format this i'm unable to get the function in the component to wait for the return of the async function before moving on.
Here is a simplified version of the utility function:
// configure and send API request using Axios library
export const retrieveTokens = async () => {
// configure request
var config = {
// configs
};
// send request
axios(config)
// handle response
.then(function (response) {
let cognitoTokens = response.data;
console.log("A:")
console.log(cognitoTokens);
return cognitoTokens;
})
// handle error
.catch(function (error) {
console.log(error);
});
};
and then this utility function is being imported into the React Class Component like so:
import React, { Component } from "react";
import { retrieveTokens } from "./utils.js";
class HeaderLogic extends Component {
componentDidMount() {
async function authenticationFlow() {
let tokens = await retrieveTokens();
console.log("B:");
console.log(tokens);
}
authenticationFlow();
}
render() {
return <></>;
}
}
export default HeaderLogic;
My expected result would be:
A:
{Tokens}
B:
{Tokens}
but I am only able to get
B:
Undefined
A:
{Tokens}
I have tried various different syntax's and I simply cannot get the console logs in authenticationFlow() to await!
You forgot to return. Also, don't declare a function as async if you don't have any await inside it (not that it causes any problem but it's just useless):
// configure and send API request using Axios library
export const retrieveTokens = () => {
// configure request
var config = {
// configs
};
// send request
return axios(config)
// handle response
.then(function (response) {
let cognitoTokens = response.data;
console.log("A:")
console.log(cognitoTokens);
return cognitoTokens;
})
// handle error
.catch(function (error) {
console.log(error);
});
};

Unable to access Variable value using nodejs exports?

Hey i have fallen into a situation where i cannot access a variable which i have set within a nodejs module which i have exposed with module exports to access from the main file, i will show you below:
Login.js:
let DEVICES;
function a() {
return DEVICES;
}
async function init() {
try {
const __devices = await _db_get_devices();
DEVICES = new DeviceCollection(__devices);
console.log(a()) <-- **Returns the object correctly**
} finally {
console.log("Login Initialised!");
}
}
module.exports = { init, a }
Below is the code that is having issues:
App.js
const Login = require('./func/Login');
Login.init() <-- **runs init function no issues**
console.log(Login.a()); <-- **returns undefined**
I have figured that its something to do with async but that is why i setup a function to call it later so not sure if there is a better method to calling the variable when its set.
init is an async function, so following statement
console.log(Login.a())
will run before init function has executed completely. Hence you get undefined because DEVICES isn't initialized yet.
You can return DEVICES from the init function and call init function as shown below
Login.init()
.then(data => console.log(data)) // log the return value of init function
.catch(error => console.log(error);
or you could call function a after init function has executed completely
Login.init()
.then(() => console.log(Login.a()))
.catch(error => console.log(error);

How to mock a node module with jest within a class?

I need to mock the DNS node module in a class but I am unsure how to do so as it is enclosed in the class. Here is a sample of what the class looks like...
import { lookup } from 'dns';
class Foo {
// ...
protected async _bar(IP: string) {
// I want to mock "lookup"
await new Promise<undefined>((resolve, reject) => {
lookup(IP, (err, addr) => {
if (err) reject(new Error('DNS Lookup failed for IP_ADDR ' + IP));
resolve();
});
});
// If dns found then return true
return true;
}
// ...
}
I would like to create a test file foo.spec.ts that contains a test similar to the following:
import { Foo } from './Foo';
describe('Foo', () => {
it('Bar Method returns true on success', () => {
const test = new Foo();
expect(test._bar('192.168.1.1')).resolves.toBeTruthy();
});
});
I am unsure how to mock the lookup call within the class Foo given that the class definition is in a separate file from the test itself.
Any help would be appreciated!
The way you are using lookup won't work since it doesn't return a Promise...
...but you can convert it to a version that does return a Promise by using util.promisify.
The code would end up looking something like this:
import { lookup as originalLookup } from 'dns'; // <= import original lookup...
import { promisify } from 'util';
const lookup = promisify(originalLookup); // <= ...and promisify it
export class Foo {
async _bar(IP: string) {
await lookup(IP).catch(err => { throw new Error('Failed'); });
return true;
}
}
You could then mock lookup in your test using jest.mock like this:
import { Foo } from './Foo';
jest.mock('dns', () => ({
lookup: (hostname, callback) => {
hostname === 'example.com' ? callback() : callback('error');
}
}))
describe('Foo', () => {
it('Bar Method returns true on success', async () => {
const test = new Foo();
await expect(test._bar('example.com')).resolves.toBeTruthy(); // Success!
await expect(test._bar('something else')).rejects.toThrowError('Failed'); // Success!
});
});
Note that the mock needs to be created using jest.mock (and not something like jest.spyOn) since calls to jest.mock get hoisted and run first. The mock needs to be in place before Foo.js is imported since the first thing it does is create and store the promisified lookup.
From jest's tutorial,
jest.mock('./sound-player', () => {
return function() {
return {playSoundFile: () => {}};
};
});
so you could do sth like jest.mock('dns', () => ({ ... }));

Pattern: How to access object.properties (correctly) from result returned by async function

I have a function that fetch data from DB or API point and add properties to it, like this:
async function function_one (arg) {
try {
if (arg != number) throw new Error('error')
let data = await findOne(arg);
data['property'] = 1+2+3
....
return data //this is an object with it's own properties
} catch (e) {
console.log(e); //errorHandling with winston
}
}
and another (master) function that use data from previous function(s):
async function Master (user_input) {
try {
let object = await function_one(user_input);
console.log(object.property_one) //weak warning
let another_object = await another_function (fixed_arg);
//some other logic with object properties.
return result_data
} catch (e) {
console.log(e);
}
}
So when I'm trying to access object properties in Master function like:
let object = await function_one(user_input);
console.log(object.property_one)
My IDE (WebStrom) shows something like that: but I know that if function_one will execute correctly (w/o catch block) this property would exist. And if Master function will fail, user won't receive a message from function_one. (IDE says that throw exception caught locally).
So what am I doing wrong and what should I do? Handle every async function in Master function like that:
async function Master (user_input) {
try {
let object = await function_one(user_input)
.then(data => {
//working with properties here and then return it?
})
.catch(error => {//handle it});
or return from function_one all properties like: return {property_one, property_two, ... }
Using destructuring assignment helps me with this problem

Angular reading the value of a js function as undefined, even when the object has value

I created some javascript functions that read and write to a json file, are suppose to be invoked in angular(from typescript code), using jsonfile library.
Here is the code:
function savePatient(patient){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json'
jsonfile.writeFile(file, patient, {flag: 'a'}, function(err){
if(err) console.error(err)
})
}
function getPatients(){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json'
jsonfile.readFile(file, function(err, obj){
if(err) console.error(err)
console.dir(obj)
return obj
})
}
Here is the declaration of functions in Angular component:
declare function savePatient(patient: Patient);
declare function getPatients(): Patient[];
I managed to successfully call the savePatient() function, and it does as intended.
When I try to invoke console.log(getPatients()) from inside the Angular component, the output is undefined, but the getPatients() function itself generates a correct console output from the console.dir(obj) line.
How am I suppose to get the correct value of the function inside the Angular component?
Also, this project is inside an electron container, if someone may find that relevant.
I found it interesting that the Angular component is the first one to output information to console, even though it would make sense that the js functions should give output before it, considering that the Angular component should be dependent on the return value of the js function, but I don't know what to make of that.
Your function
function getPatients(){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json'
jsonfile.readFile(file, function(err, obj){
if(err) console.error(err)
console.dir(obj)
return obj
})
}
works asynchronous (see docs).
You have two options. The first one is to handle the file-reading asynchronously:
function getPatients(){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json';
// Create a new promise
return new Promise((resolve, reject) => {
jsonfile.readFile(file, function(err, obj){
if(err){
console.error(err)
return reject(err);
}
console.dir(obj)
return resolve(obj);
});
});
}
...
// Prints the read object in the console, after the file reading is done
getPatients().then((obj) => {
console.dir(obj);
});
The second options, and in my opinion the best solution for you is using the synchronous way to read a file:
function getPatients(){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json'
try {
const obj = jsonfile.readFileSync(file);
console.dir(obj);
return obj;
} catch(e) {
console.error(e);
});
}
Please make sure that your function return something. In this snippet i added a return statement before jsonfile.readfile().
function getPatients(){
const jsonfile = require('jsonfile')
const file = 'src/resources/patients.json'
return jsonfile.readFile(file, function(err, obj){
if(err) return err;
return obj;
});
}

Categories

Resources