Async/await with Express returns Promise { <pending> } - node.js

I'm trying to use async/await function following some tutorials but I don't know why always returns
Promise { <pending> }
Here is my code:
function doubleAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
console.log(x);
resolve(x * 2);
}, 2000);
});
}
async function get_media_async (media_id) {
const a = await doubleAfter2Seconds(10);
return a;
}
exports.get_media = function(media_id){
var media_url = get_media_async(media_id);
return media_url;
};
Any help would be appreciated!

You need to do async/await on get_media method as well. It is because you are calling an async function get_media_async from within this method thus this needs to be async as well.
exports.get_media = async function(media_id){
var media_url = await get_media_async(media_id);
return media_url;
};

Related

async/await troubles in a recursive Redis function

Ima rookie using async/await but must now to use Redis-om. NN_walkd walks through a Redis database looking for loop-chains and does this by recursion. So the 2 questions I have is:
Am I calling the inner recursive NN_walkd calls correctly via async/await?
At runtime, the compSearchM proc is called first and seems to work (it gets 5 entries so it has to call NN_walkd 5 times). A NN_walkd is then recursively called, and then when it loops the 1st time it then calls compSearchK where the problems are. It seems to sit on the first Redis call in compSearchK (.search). Yet the code for compSearchK and compSearchM look basically identical.
main call
NN_walk = async function(req, db, cnode, pnode, chain, cb) {
var vegas, sneaker;
req.session.walk = [];
await NN_walkd(req, cnode, pnode, [], 1);
req.session.walk = null;
console.log('~~~~~~~~~~~~ Out of Walk ~~~~~~~~~~~~~~~');
cb();
};
redis.mjs
export class RedisDB {
constructor() {
...
this._companyRepo = ...
}
compSearchK(ckey) { // doesn't matter if I have a async or not here
return new Promise(async (resolve) => {
const sckey = await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
if (sckey.length) {
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
resolve(ttrr.toJSON());
} else
resolve(null);
});
}
compSearchM(mkey) {
var tArr=[];
return new Promise(async (resolve) => {
const smkey = await this._companyRepo.search()
.where('MASTERKEY').equals(mkey)
.and('TBLNUM').equals(10)
.return.all();
if (smkey.length) {
for (var spot in smkey) {
const ttrr = await this._companyRepo.fetch(smkey[spot].entityId);
tArr.push(ttrr.toJSON());
}
resolve(tArr);
} else {
resolve(null);
}
});
}
walk.js
NN_walkd = async function(req, cnode, pnode, chain, lvl) {
...
if (cnode[1]) {
const sObj = await req.app.get('redis').compSearchK(cnode[1]);
if (sObj) {
int1 = (sObj.TBLNUM==1) ? null : sObj.CLIENTKEY;
(async () => await NN_walkd(req, [sObj.COMPANYKEY,int1], cnode, Array.from(chain), tlvl))()
}
} else {
const sArr = await req.app.get('redis').compSearchM(cnode[0]);
if (sArr.length) {
for (sneaker in sArr) {
(async () => await NN_walkd(req, [sArr[sneaker].COMPANYKEY,sArr[sneaker].CLIENTKEY], cnode, Array.from(chain), tlvl))()
}
} else {
console.log('no more links on this chain: ',cnode);
}
}
}
"doesn't matter if i have async or not here"
compSearchK(ckey) { // doesn't matter if I have a async or not here
return new Promise(async (resolve) => {
const sckey = await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
if (sckey.length) {
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
resolve(ttrr.toJSON());
} else
resolve(null);
});
}
Of course it doesn't matter, because you're not using await inside of compSearchK!
You are using the explicit promise contructor anti-pattern. You should avoid it as it demonstrates lack of understanding. Here is compSearchK rewritten without the anti-pattern -
async compSearchK(ckey) {
// await key
const sckey =
await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
// return null if key is not found
if (sckey.length == 0) return null;
// otherwise get ttrr
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
// return ttrr as json
return ttrr.toJSON();
}

How can I get the completed value of an async function when calling a function from index.js?

I'm new to node and I'm trying to create a function to make API requests with pagination. The function successfully gives me the desired output, but I'm confused as to how I can use the .then() function in index.js as it's async. If I use await in my index.js then it throws an error. I hoping to get some guidance as to how I can fix this, and how I can understand async/await better.
//hs-api.js
const request = require('request-promise');
const settings = require('./settings');
var all = []
let getReq = async (url) => {
var options = {
'method': 'GET',
'url': url,
'headers': {
'Content-Type': 'application/json'
}
}
let results = await request(options, function async (error, response) {
if (error) {
reject(error)
} else {
res = JSON.parse(response.body)
}
})
all = all.concat(res.results)
if(res.hasOwnProperty("paging")) {
await getReq(`${res.paging.next.link}&apikey=${settings.api_key}`)
} else {
console.log(all)
return all
}
}
Here is where I call the function
//index.js
let apiResponse = api.getReq(`https://apiexample.com/?apikey=${settings.api_key}`)
console.log(apiResponse)
As of today (Node.js 14), you need to wrap it in a function.
Something like this
(async () => {
let apiResponse = await api.getReq(`https://apiexample.com/?apikey=${settings.api_key}`)
console.log(apiResponse)
})()
There is a proposal for ES for top-level await which will make it possible to run
let apiResponse = await api.getReq(`https://apiexample.com/?apikey=${settings.api_key}`)
console.log(apiResponse)
without wrapping it in an async function.
Node.js (since version 10) has an experimental support for this feature. You need to run it with --experimental-repl-await flag
You need to wrap it in async function in index.js.
// index.js
async someFn() {
let apiResponse = await api.getReq(`https://apiexample.com/?apikey=${settings.api_key}`)
console.log(apiResponse)
}
// call
someFn();
or use '.then'
api.getReq(`https://apiexample.com/?apikey=${settings.api_key}`)
.then(apiResponse => {
console.log(apiResponse);
})
.catch(console.log);
UPD:
//hs-api.js
const results = await request(options);
// don`t sure, that it is correct error indicator for your library
if(result.error) {
throw new Error(// describe error here);
}
const res = JSON.parse(response.body);
all = all.concat(res.results);
if(res.hasOwnProperty("paging")) {
return await getReq(`${res.paging.next.link}&apikey=${settings.api_key}`)
} else {
console.log(all);
return all;
}

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] ]

Calling asynchronous recursive functions in Node.js with Promise

at first i need to say im pretty new to electron and node.js.
What i am doing is im trying to send an array with some directory data to my browser and this asynchronous (Error: array is empty).
The Problem should be my function 'scanDirectories(path)'.
If i make it non recursive (scanDirectories(res) -> only return res) it works pretty fine for 1 level directories, but recursive it doesnt.
So i think i need to do it like my function above with returning a new promise?
I tried it but can´t figure out how it works or my syntax should be.
Hope you can help me.
Simon
main.js:
calling function from ipcmain
ipcMain.on('fileTree', (event, arg) => {
let fileDirectory = helperFile.getDirectories(arg);
fileDirectory.then(function(result) {
event.reply('fileTree', result);
}, function(err) {
console.log(err);
})
})
files.js
const { readdir } = require('fs').promises;
const resolvePath = require('path').resolve;
module.exports = {
getDirectories: async function(path) {
return new Promise(function (resolve, reject) {
try {
resolve(scanDirectories(path));
} catch {
reject('Error');
}
});
}
};
async function scanDirectories(path) {
const dirents = await readdir(path, {withFileTypes: true});
const files = dirents.map((dirent) => {
const res = resolvePath(path, dirent.name);
return dirent.isDirectory() ? scanDirectories(res) : res;
});
return Array.prototype.concat(...files);
}
You can try something like this where you generate an array of promises:
files.js
const { readdir } = require('fs').promises;
const resolvePath = require('path').resolve;
module.exports = {
// This is an async function so don’t need internal promise
getDirectories: async function(path) {
try {
const dirs = await scanDirectories(path);
return dirs;
}
catch {
throw new Error('Error');
}
}
};
async function scanDirectories(path) {
const dirents = await readdir(path, {withFileTypes: true});
// Generate array of promises
const promises = dirents.map(dirent => {
const res = resolvePath(path, dirent.name);
return dirent.isDirectory()
? scanDirectories(res)
: Promise.resolve(res);
});
// Await all promises
const files = await Promise.all(promises);
return Array.prototype.concat(...files);
}
If you call an async function without await, you receive a promise.
Your event handler handles this sort-of-OK with then (it has trouble with error handling), but your recursive call to scanDirectories does not.
The simplest way to wait for an async function to resolve is to use await.
So this change makes the recursive call properly:
return dirent.isDirectory() ? (await scanDirectories(res)) : res;
Note the addition of await.
However "Array.map" is not designed for use in async functions. It will call them synchronously and create an array of promises. Not what you want.
In addition, this code is unnecessarily complicated, wrapping a promise in a promise and using try/catch in a way that won't work:
getDirectories: async function(path) {
return new Promise(function (resolve, reject) {
try {
resolve(scanDirectories(path));
} catch {
reject('Error');
}
});
}
Just call scanDirectories directly from your original event handler, and make the event handler an async function, so a lot of code just goes away.
In general: if you have to deal with async stuff, write an async function, and always await it in the function that calls it, even if that function is itself. You may write async functions anywhere, even if they are event handlers or Express routes or other contexts where the promise they resolve to won't be consumed.
Here is your original code simplified and corrected but working basically the same way:
ipcMain.on('fileTree', async (event, arg) => {
try {
event.reply('fileTree', await helperFile.scanDirectories(arg);
} catch (e) {
console.log(e);
}
});
// files.js
const { readdir } = require('fs').promises;
const resolvePath = require('path').resolve;
module.exports = {
scanDirectories: async function(path) {
const dirents = await readdir(path, { withFileTypes: true });
const files = [];
for (const dirent of dirents) {
const res = resolvePath(path, dirent.name);
if (dirent.isDirectory()) {
files = files.concat(await scanDirectories(res));
} else {
files.push(res);
}
});
return files;
}
}

I cannot implement an async function

I've started working with protractor-cucumber automation testing (https://github.com/mlev/protractor-cucumber-example), previously in one of my other projects I had no issue implementing async await functions, however, in this case I cannot.
This is my current semi-working (protractor outpust completed for all tasks, however it will not wait at browser.sleep) code:
I have tried nodes async await libary and the following code:
this.get = async function someName(){
await browser.get('https://translate.google.com/');
};
this.Given('The Translate is open', async function (callback) {
await this.page.get();
callback();
}
StepsDef:
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
var TranslateSteps = function() {
var TranslatePage = require("../pages/translate_page");
this.World = function MyWorld() {
this.page = new TranslatePage();
};
this.Given('The Translate is open', function (callback) {
this.page.get();
callback();
}
)
this.Then('I wait $string seconds', function (string) {
browser.sleep(string * 10000)
}
};
module.exports = TranslateSteps;
Page:
var TranslatePage = function() {
this.get = function (){
browser.get('https://translate.google.com/');
};
this.setInputBox = function (value) {
element(by.className("gt-hl-layer")).sendKeys(value)
console.log("setInput")
};
this.clickLang = function () {
element(by.className("sl-more tlid-open-source-language-list")).click()
console.log("clickLang")
}
};
module.exports = TranslatePage;
most of the time I got error code 1 or 100, at times i got no 199.
Firstly make sure that you disable promise manager by adding this SELENIUM_PROMISE_MANAGER: false line in the protractor.conf.js file.
You don't need to use the callback function.
this.get = async function() {
await browser.get('https://translate.google.com/');
};
this.Given('The Translate is open', async function() {
await this.page.get();
});
As I said above you don't need the callback function. Alson the sleep method expects number type instead of the string.
var TranslateSteps = function() {
var TranslatePage = require("../pages/translate_page");
this.World = function MyWorld() {
this.page = new TranslatePage();
};
this.Given('The Translate is open', async function() {
await this.page.get();
});
this.Then('I wait {num} seconds', async function(num) {
await browser.sleep(num * 10000)
});
};
Add async/await's.
var TranslatePage = function() {
this.get = async function() {
await browser.get('https://translate.google.com/');
};
this.setInputBox = async function(value) {
await element(by.className("gt-hl-layer")).sendKeys(value)
await console.log("setInput")
};
this.clickLang = async function() {
await element(by.className("sl-more tlid-open-source-language-list")).click()
await console.log("clickLang")
}
};
module.exports = TranslatePage;
this.When('I enter $string', async function myF(string) {
await this.page.setFirstValue(string);
return true;
});
and:
this.setFirstValue = async function asd(value) {
await element(by.className('orig tlid-source-text-input goog-textarea')).sendKeys(value);
};
works like a charm

Resources