Returning a Promise in Node.js - node.js

I can't wrap my head around this.
Take the following three functions where a calls b, and b calls c:
const c = () => {
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve(new Date());
}, "1750");
});
};
const b = async () => {
const result = await c();
console.log("b(): %s", result);
return result;
};
const a = async () => {
const result = await b();
console.log("a(): %s",result);
return result;
};
console.log("Starting...");
const final_result = a();
console.log("Final Result: %s", final_result);
console.log("Ending...");
I expected b() to wait-for/get the result of the promise returned by c(), and pass the value to a(). However, it looks like the promise gets passed all the way up the call stack.
To get the behavior I want, I have to handle the promise in each function:
const c = () => {
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve(new Date());
}, "1750");
});
};
const b = async () => {
const result = await c();
console.log("b(): %s", result);
return result;
};
const a = async () => {
const result = await b();
console.log("a(): %s",result);
return result;
};
(async () => {
console.log("Starting...");
const final_result = await a();
console.log("Final Result: %s", final_result);
console.log("Ending...");
})()
Why can't I just get the result of the promise in one function and return that? And, if I can do it, how?

Related

Node measure execution time - return value from an async passed as parameter to another function

I want to write a function to measure the performance of parts of code (other methods) that could return a value. This is what I came out at the moment:
const fn = async (): Promise<any> => {
setTimeout(async (): Promise<any> => {
return new Promise((resolve) => resolve('Hello World!'));
}, 3000);
};
async measure(fn: () => Promise<any>): Promise<any> {
const startTime = this.performance.now();
const result = await functionToMeasure();
const endTime = this.performance.now();
const executionTime = endTime - startTime;
console.log(`Executed in ${executionTime} ms`);
return result;
}
const result = async measure(functionToMeasure); // result is undefined
The result is that functionToMeasure actually runs but it never returns something and at the moment I can use it only with void function.
I'd like to fix it if possible, or I can change completely if there's a better way to do it.
EDIT:
Actual code
const callback = async (): Promise<any> => {
return await doSomethingAndReturn();
};
const searchResults: string[] = await measure(callback);
Do I've to wrap doSomethingAndReturn in an async Promise?
You need to wrap the setTimeout call in a promise and then resolve the result, so it should look something like this:
const {performance} = require('perf_hooks');
async function executeAndMeasure(fn) {
const startTime = performance.now();
const result = await fn();
const endTime = performance.now();
const executionTime = endTime - startTime;
console.log(`Executed in ${executionTime} ms`);
return result;
}
function someFnThatReturnsAPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve("Hello World");
}, 3000);
})
}
async function someAsyncFunction() {
return 123;
}
(async () => {
let result = await executeAndMeasure(someFnThatReturnsAPromise);
console.log(`result was ${result}`);
result = await executeAndMeasure(someAsyncFunction);
console.log(`result was ${result}`);
})();

Strange Promise.all behaviour

In one file called SearchBuilder.js i have this function ( wrote in this way as pure test )
self.validateInputs = async params => {
const validateDates = async () => {
const pick_up_date = moment(`${params.pick_up_date} ${params.pick_up_time}`),
drop_off_date = moment(`${params.drop_off_date} ${params.drop_off_date}`);
return true;
};
const validatePickUpId = async () => {
return true;
};
const validateDropOffId = async () => {
throw { 'code': 'NOT_FOUND'};
};
return Promise.all([
validateDates,
validatePickUpId,
validateDropOffId,
]);
};
In another file called searchEngine.js i have this:
self.run = async (type, search_inputs, account) => {
const searchBuilder = self.getSearchBuilder(type);
try {
const isValid = await searchBuilder.validateInputs(search_inputs);
console.log(isValid);
} catch (e) {
console.log('error input validation');
}
return search;
};
I erroneously thought that if any of the promises in Promise.all would fail, so my code will enter the catch block. Instead, even if the promise fails code inside the catch is never executed and inside isValid i get this.
[ [AsyncFunction: validateDates],
[AsyncFunction: validatePickUpId],
[AsyncFunction: validateDropOffId] ]

cant return the chained promises result

const request = require('request-promise')
required this module and use it in this way the data and subData is options that i defined later...
const foo= (data, subData) => {
return request(data)
.then(result => {
console.log('result:',result)
return request(subData)
})
}
the problem is the request(data) result is not return but the request(subData) result is return
Q.allSettled([
foo(),
fo(),
f(),
.
.
.
])
and with q module create an array of promises, but i still cant get my expected return result
You can use any of the following methods to chain your promises and return both responses into an array
const foo = (data, subData) => {
let result;
return request(data)
.then(res => {
result = res;
return request(subData)
}).then(res => {
return [result, res]
});
}
//OR
const foo2 = (data, subData) => {
return request(data)
.then(res1 => {
return request(subData).then(res2 => {
return [res1, res2]
})
});
}
//OR
const foo3 = async (data, subData) => {
let res1 = await request(data);
let res2 = await request(subData);
return [res1, re2];
}
I would suggest the following approach instead of Promise Chaining or Q:
const fetchData = (data, subData) => {
const result = await request(data);
const resultSub = await request(subData);
console.log(result, resultSub);
};

Why isn't my Async Await flow not showing the results expected?

Im using Async on getJsonProducts, and I'm awaiting before console.log(products) but it still prints undefined. I thought await, pauses until the promise has been resolved?
Why aren't the products visible?
async function getJsonProducts(){
let products;
await fs.readFile('./products.json','utf-8',async (err,data)=>{
if(err)
throw err;
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = await data.replace(r,'');
d = await d.split('\n');d.pop();
products = await d.map(s=>JSON.parse(s));
//console.log(products) prints here
})
await console.log(products); //prints undefined here?
}
const seedProducts = async () => {
await getJsonProducts();
}
seedProducts();
I know there's other ways to implement this but I want to understand why this isn't working.
absolutely you will get undefined because you combined between async-await and the callback, also this is not how async-await works,
if you want to use async await , you can follow my code
async function getJsonProducts() {
return new Promise((reoslve, reject) => {
fs.readFile('./products.json', 'utf-8', async (err, data) => {
if (err) reject(err)
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = data.replace(r, '');
d = d.split('\n');
d.pop();
const products = d.map(s => JSON.parse(s));
resolve(products)
})
})
}
const seedProducts = async () => {
const products = await getJsonProducts();
conosle.log(products); // you will get products
}
seedProducts();
function getFile(cb) {
fs.readFile('./products.json', 'utf-8', (err, data) => {
if (err)
throw err;
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = data.replace(r, '');
d = d.split('\n');
d.pop();
cb(d.map(s => JSON.parse(s)));
})
}
async function getJsonProducts() {
this.getFile(products => console.log(products));
}
const seedProducts = async () => {
await getJsonProducts();
}
seedProducts();

How to stub oracledb with sinon?

Here is my function which will return a promise once it gets data from oracle database:
const getDataFromOracleDB = (filter, query) =>
new Promise(async (resolve, reject) => {
let conn;
try {
conn = await oracledb.getConnection(dbConfig);
const result = await conn.execute(query, [filter]);
const { rows } = result;
...
catch (err) {
...
}
};
As the unit test, I want to stub conn.execute, but have no idea how to do that. I've treid:
const stub = sinon.stub(conn, 'execute').returns([1, 2, 3]);
But got:
TypeError: Cannot stub non-existent own property execute
Any suggestions?
I can't replicate the error with the code you supplied, but perhaps this quick mockup will help:
const chai = require('chai');
const sinon = require('sinon');
const oracledb = require('oracledb');
const config = require('./dbConfig.js');
const expect = chai.expect;
sinon.stub(oracledb, 'getConnection').resolves({
execute: function() {},
close: function() {}
});
describe('Parent', () => {
describe('child', () => {
it('should work', async (done) => {
let conn;
try {
conn = await oracledb.getConnection(config);
sinon.stub(conn, 'execute').resolves({
rows: [[2]]
});
let result = await conn.execute(
'select 1 from dual'
);
expect(result.rows[0][0]).to.equal(2);
done();
} catch (err) {
done(err);
} finally {
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
});
});
});
The query would normally return a value of 1, but this returns 2 and passes.

Resources