console.log not logging with await variable - javascript

I am trying to log the data of a promise to my console but it's not showing. i have tried defining then in then and on top of functions and tried with let and redefining the before executing the algorithm but. no response
sample
var trade;
const getTrades = async () => {
return await axios({
method: 'get',
url: bUrl + tradeQuery
})
}
const getSOrders = async () => {
return await axios({
method: 'get',
url: bUrl + mOrderQuery
})
}
const postOrder = async() => {
const binanceRest = new api.BinanceRest({
...
}
)
binanceRest.newOrder({
...
})
.then(async(data) => {
const trades = await getTrades()
const mOrders = await getSOrders()
console.log(data)
console.log(trades)
})
.catch((err) => {
console.error(err)
})
}
(
postOrder(),
async () => {
const trades = await getTrades()
const mOrders = await getSOrders()
const sells = mOrders.data.asks
const buys = mOrders.data.bids
while (true/*while order is in */) {
trade = trades.data[trades.data.length - 1]
console.log(sells)
}
}
)()

Your code is stuck in a an infinite while loop. Since node is single threaded, it will continue to execute the loop until broken and never execute the .then code in the original promise. You should be able to easily see this by commenting out the while loop.
Specifically:
binanceRest.newOrder is async call. It's true that postOrder is called first, but depending on the how nodejs decides to optimize, all of the awaits are hit at the same time. When the awaits resolve, if Nodejs decides that postOrders will resume your console.log will write, however if the while loop it hit first, then your program will be stuck there.

I'm sorry to say this, but I can see a lot of confusing things in this code.
while(true) {
trade = trades.data[trades.data.length - 1];
console.log(sells);
}
this will never exits. If you omitted part of your code is not a good idea as this makes us harder to give you the actual answer to your question. If this is your real code, I would change in
while(trades.data.length) {
trade = trades.data.pop();
console.log(sells);
}
postOrder is an async function which deals with Promise, and this is confusing: I would rewrite it as
const postOrder = async() => {
try {
const binanceRest = new api.BinanceRest({ ... });
const data = await binanceRest.newOrder({ ... });
const trades = await getTrades()
const mOrders = await getSOrders()
console.log(data)
console.log(trades)
}
catch(err) {
console.error(err)
}
}
Last postOrder is an async function which is called without await and this is source of confusion as well.
I would start cleaning your code, probably many problem will be solved as well.
Hope this helps.

Is not an "await" problem
I've added a bunch of console.log instructions at your code and there's no problem printing anything. Try adding the same to your original code, assuming your API's are working fine there's no reason for failure.
The following snippet mocks your API's, please take a look at the result. Your error must be at your logic, api's or syntax.
Also add a safe break inside your while, something like this: if (calls++ > 5) { break; }, to me it seems that the infinite loop is the problem.
/* MOCK API'S */
let test = 0, calls = 0;
const fakePromise = (arg, apiName) => { return { then: (f1, f2) => { console.log('mocked result for ' + apiName); return f1(arg); } }; };
const axios = (args) => { console.log('-> axios is called', args); return fakePromise({data: { asks: ['ask'], bids: ['bid'], length: 1, 0: 'fake index'} }, args.url); };
const api = { BinanceRest: function(){ return { newOrder: () => fakePromise(' -> newOrder result <- ', 'newOrder')}; } };
const bUrl = 'bUrl/', mOrderQuery = 'mOrderQuery', tradeQuery = 'tradeQuery';
/* YOUR CODE STARTS HERE */
var trade;
const getTrades = async () => {
console.log('-> getTrades is called');
return await axios({
method: 'get',
url: bUrl + tradeQuery
});
}
const getSOrders = async () => {
console.log('-> getSOrders is called');
return await axios({
method: 'get',
url: bUrl + mOrderQuery
})
}
const postOrder = async() => {
console.log('step 1');
const binanceRest = new api.BinanceRest({
// ...
});
console.log('step 2');
binanceRest.newOrder({
// ...
})
.then(async(data) => {
console.log('step 3');
const trades = await getTrades()
const mOrders = await getSOrders()
console.log('step 4.2');
console.log('data: ', data)
console.log('trades: ', trades)
console.log('mOrders', mOrders)
})
.catch((err) => {
console.error(err)
})
}
// test
(
postOrder(),
async () => {
console.log('step 4.1');
const trades = await getTrades()
const mOrders = await getSOrders()
console.log('step 5', mOrders);
const sells = mOrders.data.asks
const buys = mOrders.data.bids
console.log('step 5.0');
while (true/*while order is in */) {
console.log('step 5.' + (test++));
trade = trades.data[trades.data.length - 1]
console.log('sells: ', sells)
if (calls++ > 5) {
console.log('way too much calls, break! ');
break;
}
}
}
)()

Take a closer look at your postOrder func:
const postOrder = async() => {
const binanceRest = new api.BinanceRest({ ... })
binanceRest.newOrder({ ... })
.then(...)
.catch(...)
}
Now imagine the scenario when a typo has been made, f.e. it should be new api.FinanceRest(...) and as a result you end up with error:
Uncaught (in promise) TypeError: api.BinanceRest is not a function
Rest of code in postOrder is simply skipped, no console.logs. So the main point here: if in new api.BinanceRest({ ... }) something leads to an error (any error) than you'll end up with situation you have right now.
And also worth to mention that an async anonymous function with while loop still gets executed and that's because postOrder is an async func which means it returns a pending Promise.
Try running this in you browsers console to get more sense of what's goin' on:
function delay(sec) {
return new Promise((res, rej) => {
setTimeout(() => res("delay " + sec + "sec"), sec * 1000);
});
}
async function getTrades() {
return await delay(0.1);
};
async function getSOrders () {
return await delay(0.2);
};
async function postOrder() {
console.log("postOrder");
const api = {};
const binanceRest = api.BinanceRest()
delay(0.4)
.then(async (data) => {
console.log("postOrder result")
const trades = await getTrades()
const mOrders = await getSOrders()
console.log(trades)
console.log(mOrders)
})
.catch(err => {
console.error(err);
});
};
(postOrder(),
async () => {
const trades = await getTrades();
const mOrders = await getSOrders();
console.log("gfdfg");
})();

Related

Cheerio. Can't get data inside TRY body after handling error of another function

There is a code like this:
const axios = require('axios');
const cheerio = require('cheerio');
let data = null;
const parseNewCorporations = async (iter) => {
let link2 = 'https://www.finanzen.net/aktien/' + iter.finanzen_net + '-aktie';
try{
await axios.get(link2)
.then(res => res.data)
.then(res => {
let html = res;
$ = cheerio.load( html, { decodeEntities: false } );
let bigData = iter;
let price = $('div.snapshot-headline div.col-sm-7 div.row.quotebox:first-child div.col-xs-5.col-sm-4.text-sm-right.text-nowrap').text();
let currency = $('div.snapshot-headline div.col-sm-7 div.row.quotebox:first-child div.col-xs-5.col-sm-4.text-sm-right.text-nowrap span').text();
price = price.replace(currency, '').replace(',', '.');
})
}
catch(e){
console.log(e.message, ', id =', iter.id, ", finanzen_net = "+iter.finanzen_net);
await getAdditionPriceBilanzGuv(iter);
}
};
const getAdditionPriceBilanzGuv = async (iter) => {
//console.log('111', iter); // **here the code works correctly**
let link = 'https://www.finanzen.net/bilanz_guv/'+ iter.finanzen_net;
try{
await axios.get(link)
.then(res => res.data)
.then(res => {
console.log('getAdditionPriceBilanzGuv', iter);
// **here the code works NOT correctly**
})
}
catch(e){
if(e.message == 'Request path contains unescaped characters'){
console.log('Request path contains unescaped characters');
console.log({paramSubLink: iter.finanzen_net, corporations_id: iter.id});
}
else{
console.log('paramCorporationsId: ', iter.id);
//console.log('err- ', e);
}
}
};
function getApiData(){
// get request
return axios.get("https://seo-gmbh.eu/invest/daily.php" , {
})
.then(response => {
return response.data;
})
.catch(function (error) {
console.log(error);
});
}
async function new_corporations() {
data = await getApiData();
let ii = 1;
for (let iter of data.new_corporations) {
//await parseNewCorporations(iter);
ii++;
await setTimeout(function(){
parseNewCorporations(iter);
}, ii*3000);
}
//console.log(arrayCurrency);
}
new_corporations();
After calling the parseNewCorporations () function, the catch () exception is triggered as a result of which
the corresponding messages can be seen in the console.
The problem is that when this error appears, you need to run the following function getAdditionPriceBilanzGuv () with the iter parameter, and inside the body oftry {}you need to get this parameter, which cannot be done.
At the very beginning (outside the body of try {}) of this function (where it is indicated by a comment that the code works), it is possible to get this parameter.
Question:
What am I missing and how can I get this parameter in a newly called function inside the body of try {}?
If it is impossible to do this, what alternative implementations can be for solving this problem?
P.S. In this case, a parsing library is used cheerio
If you use async / await, you don't want thens
let res = await axios.get(link2)
let $ = cheerio.load(res.data)

trouble with a while loop

Im trying to use a while loop with my util() function (its commented out at the bottom of the code). When I try to run the program, I am stuck in an endless loop where i dont get farther than where I'm console logging out "getProjects running"
const axios = require("axios");
const _ = require("lodash");
axios.defaults.headers.common["Private-Token"] = "iTookMyPrivateKeyOut";
const user = "yshuman1";
let projectArray = [];
let reposExist = true;
async function getProjects() {
console.log("getProjects running");
await axios
.get(`https://gitlab.com/api/v4/users/${user}/projects`)
.then(function(response) {
const arr = _.map(response.data, "id").forEach(repo => {
projectArray.push(repo);
});
console.log(projectArray);
});
}
function deleteRepo(projectArray) {
console.log("array size", projectArray.length);
const arr = _.map(projectArray).forEach(item => {
axios
.delete(`https://gitlab.com/api/v4/projects/${item}`)
.then(() => {
console.log("deleted project ID: ", item);
})
.catch(error => {
console.log(error);
});
});
}
function util() {
getProjects()
.then(() => {
if (projectArray.length == 0) {
reposExist = false;
}
if (projectArray.length < 20) {
console.log("array is less than 20");
reposExist = false;
}
deleteRepo(projectArray);
})
.catch(error => {
console.log(error);
});
}
// while (reposExist) {
// util();
// }
The while loop is synchronous, while everything in any .then (or promise await) will be asynchronous. The initial thread will never terminate. Your code will simply queue up unlimited calls of getProjects which will only console.log.
The simple solution would be to figure out how often you want to call util (once a second? once every 5 seconds?) and await a Promise that resolves after that amount of time on each iteration.
let reposExist = true;
function util() {
console.log('running');
}
const resolveAfter5 = () => new Promise(res => setTimeout(res, 5000));
(async () => {
while (reposExist) {
util();
await resolveAfter5();
}
})();

JS return doesn't wait for await [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 4 years ago.
I am trying to use the async await.
My app starts like this
axios.get(`${ROOT_URL}/ccidxann.php`)
.catch(err => console.error('axios error get', err))
.then(async res => {
const html = res.data
const jobList = await getJobList(html)
console.log(' after each jobList', jobList)
// jsonfile.writeFileSync('jobs.json', jobList, { flag: 'a' })
})
.catch(err => console.error(err))
The problem is that jobList is always returned as an empty array.
Here is the getJobList function
async function getJobList (html) {
const jobList = []
const dom = new JSDOM(html)
const { window } = dom
const $ = require('jquery')(window)
const jobsInDom = $('table').first().find('td > a')
// AWAIT HERE
await jobsInDom.each(async function (index, jobElem) {
const name = $(jobElem).text()
const url = $(jobElem).attr('href')
// Another AWAIT HERE
const jobDetailsHTML = await getJobDetailsHTML(`${ROOT_URL}/${url}`)
.catch(err => console.error('getJobDetailsHTML err', err))
const domDetails = new JSDOM(jobDetailsHTML)
const { window: windowDetails } = domDetails
const $details = require('jquery')(windowDetails)
const jobDetailsHTMLBody = $details('body').prop('outerHTML')
jobList.push({
_id: url,
name,
detailsHTML: jobDetailsHTMLBody
})
console.log('in each jobList', jobList)
}) //each
return jobList
}
As you can see I put the async keyword in front of it,
and I have put the async keyword in the callback of each
and put await in front of all async operations.
The console.log in the callback of each prints the array filled with values
but it seems the return works before the each
even with await keyword in front of it.
And also here is getJobDetailsHTML just in case. It's a simple function and seems to work just fine
async function getJobDetailsHTML (url) {
// ANOTHER AWAIT HERE
return await axios.get(url).data
}
I think jobsInDom.each is synchronous function, so putting await before doesn't give you desired effect. So somehow you need to get promise which resolved when processing is finished for all jobs, like this:
// handles one element and returns promise
const jobHandler = async jobElem => {
const name = $(jobElem).text()
const url = $(jobElem).attr('href')
const jobDetailsHTML = await getJobDetailsHTML(`${ROOT_URL}/${url}`)
.catch(err => console.error('getJobDetailsHTML err', err))
const domDetails = new JSDOM(jobDetailsHTML)
const { window: windowDetails } = domDetails
const $details = require('jquery')(windowDetails)
const jobDetailsHTMLBody = $details('body').prop('outerHTML')
jobList.push({
_id: url,
name,
detailsHTML: jobDetailsHTMLBody
})
console.log('in each jobList', jobList)
}
const promises = [];
// start processing of each element
jobsInDom.each((index, jobElem) => promises.push(jobHandler(jobElem));
// wait for processing of all job elements
await Promise.all(promises);

Execute code after fs.writeFile using async/await

I have a function, startSurvey, which, when run, checks if there are questions in a .json file. If there are no questions, it fetches some questions from Typeform and writes them to the .json file using saveForm. After it writes, I would like to continue executing some code that reads the .json file and logs its contents. Right now, await saveForm() never resolves.
I have promisified the fs.readFile and fs.writeFile functions.
//typeform-getter.js
const fs = require('fs')
const util = require('util')
const fetch = require('cross-fetch')
require('dotenv').config()
const conf = require('../../private/conf.json')
const typeformToken = conf.tokens.typeform
const writeFile = util.promisify(fs.writeFile)
const getForm = async () => {
const form = await fetch(`https://api.typeform.com/forms/${process.env.FORM_ID}`, {
headers: {
"Authorization": `bearer ${typeformToken}`
}
}).then(res => res.json())
const fields = form.fields
return fields
}
const saveForm = async () => {
const form = await getForm()
return writeFile(__dirname + '/../data/questions.json', JSON.stringify(form))
.then((e) => {
if (e) console.error(e)
else console.log('questions saved')
return
})
}
module.exports = saveForm
//controller.js
const fs = require('fs')
const util = require('util')
const request = require('request')
require('dotenv').config()
const typeformGetter = require('./functions/typeform-getter')
const readFile = util.promisify(fs.readFile)
const saveForm = util.promisify(typeformGetter)
let counter = 1
const data = []
const getQuestions = async() => {
console.log('called')
try {
let data = await readFile(__dirname + '/data/questions.json')
data = JSON.parse(data)
return data
} catch (e) {
console.error('error getting questions from read file', e)
}
}
const startSurvey = async (ctx) => {
try {
const questions = await getQuestions()
if (!questions) await saveForm()
console.log(questions) //NEVER LOGS
} catch (error) {
console.error('error: ', error)
}
}
startSurvey() //function called
I don't know your exact error, but there are multiple things wrong with your code:
You're using incorrectly the promisified version of fs.writeFile, if an error occurs, the promise will be rejected, you won't get a resolved promise with an error as the resolved value, which is what you're doing.
Use path.join instead of concatenating paths.
In startSurvey, you're using console.log(questions) but that wont have any data if questions.json doesn't exists, which should happen the first time you run the program, since it's filled by saveForm, so you probably want to return the questions in saveForm
So saveForm should look something like this:
const saveForm = async () => {
const form = await getForm();
const filePath = path.join(path.__dirname, '..', 'data', 'questions.json');
await writeFile(filePath, JSON.stringify(form));
console.log('questions saved');
return form;
}
And startSurvey
const startSurvey = async (ctx) => {
try {
const questions = await getQuestions() || await saveForm();
// This will be logged, unless saveForm rejects
// In your code getQuestions always resolves
console.log(questions);
} catch (error) {
console.error('error: ', error)
}
}
In your controller.js you're using util.promisify on saveForm when it is already a promise.
So it should be:
const saveForm = require('./functions/typeform-getter')

Using await in then callback - the keyword 'await' is reserved

In node.js, I have a database transaction, where I want to call an async method in then callback, but I get error message the keyword 'await' is reserved.
This is async saveImage function:
const saveImage = async (parsedLink) => {
AWS.config.region = config.awsSettings.region;
AWS.config.accessKeyId = config.awsSettings.accessKeyId;
AWS.config.secretAccessKey = config.awsSettings.secretAccessKey;
const bucket = new AWS.S3({
params: {
Bucket: config.awsSettings.images_bucket_name,
},
});
const currentDateString = new Date().toISOString().replace(/\:|\./g, '-');
const bodystream = new Buffer(parsedLink.imgUrl, 'binary');
const imageUrlDomain = parseDomain(parsedLink.linkUrl).domain;
const params = {
Key: `${parsedLink.id}/${imageUrlDomain}_${currentDateString}${parsedLink.imgType}`,
ContentType: parsedLink.imageMime,
ContentEncoding: 'base64',
Body: bodystream,
};
const resultPromise = await bucket.upload(params).promise();
return resultPromise.Location;
};
If I want to use saveImage function, I get the error message.
module.exports.addTestObject = async (ctx) => {
const testObj = ctx.request.body;
try {
switch (testObj.type) {
case interestT.getType.link: {
const knexTestObject = TestObject.knex();
transaction(knexTestObject, trx =>
TestObject.query(trx)
.insert({
interestDate: testObj.date,
})
.then(newInterest => {
// save image
if (parsedLink.saveImg) {
parsedLink.imgUrl = await saveImage(testObj);
}
newInterest.$relatedQuery('linkInterestsRel', trx).insert({
linkHeader: testObj.linkHeader,
}),
}
),
)
.then((linkInterest) => {
console.log(linkInterest);
})
.catch((err) => {
throw err;
});
break;
}
default:
break;
}
ctx.response.body = interestObj;
} catch (err) {
const statusCode = err.status || 400;
ctx.throw(statusCode, err.message);
}
};
Regular functions run synchronously till they return. Therefore you cannot use await inside them as you cannot wait for an asynchronous event in a synchronous way.
JavaScript also has async functions, which look like regular functions, but are conceptually quite different: They run synchronously till they reach an await, then they stop and continue once the awaited Promise resolves. As such they cannot return their result synchronously, instead they return a Promise which then resolves when the function finished execution.
Therefore you need to convert your function into an async function:
async function getUsername() { // <-- async keyword here
return (await getUser()).name; // <-- await can be used inside
}
Now this does also work inside a .then callback:
getUser().then(async function(user) {
const friends = await getFriends(user);
// ...
})
But this somewhat mixes the abstraction async functions with their underlying primitive Promise. If you would just await the Promise instead of adding a .then callback, the code gets way more readable:
(async function() {
const user = await getUser();
const friends = await getFriends(user);
})();
The concrete question could be rewritten as:
const linkInterest = await transaction(knexTestObject, async trx => {
const newInterest = await TestObject.query(trx)
.insert({ interestDate: testObj.date, });
if (parsedLink.saveImg) {
parsedLink.imgUrl = await saveImage(testObj);
}
await newInterest.$relatedQuery('linkInterestsRel', trx)
.insert({ linkHeader: testObj.linkHeader, }),
});

Categories