How to call a function after the other function is done? - javascript

My problem is that i coded a simple overstock function for my game-items trading site (site working with socket.io!). And when the site is loading, two functions getting user and site inventories with items and listing them into two boxes, but the user inv loads faster and info about overstock comes later as the bot inv is loaded. I need to execute the "get user inventory" function after the "get bot inventory" function is fully done. I tried to set a sleep function between them, but it worked only for the main function that loading whole functions. In other words sleep(2000) delays loading both inventories when it set between this two functions.
sorry for my bad english :-D
Aaand there is my code (i left only important part):
io.on('connection', (socket) => {
var userObject = false
if (
typeof socket.handshake.session.passport !== 'undefined' &&
typeof socket.handshake.session.passport.user !== 'undefined' &&
typeof socket.handshake.session.passport.user.id !== 'undefined'
) {
userObject = socket.handshake.session.passport.user
}
socket.emit('site', config.site)
socket.emit('user', userObject)
socket.on('get bot inv', (id) => {
Trade.getInventory(config.bots[id].steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('bot inv', { error: err, items: data })
})
})
socket.on('get user inv', (steamID64) => {
Trade.getInventory(steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('user inv', { error: err, items: data })
})
})
socket.on('get bots inv', () => {
const params = []
Object.keys(config.bots).forEach((index) => {
const bot = config.bots[index]
params.push({
id: index,
steamID64: bot.steamID64,
appID: config.appID,
contextID: config.contextID,
})
})
Trade.getInventories(params, (data) => {
socket.emit('bots inv', data)
socket.emit('bots floats', Trade.getFloatValues())
})
})
})

Look into promises.
var promise1 = new Promsie((resolve, reject) => {
socket.on('get bot inv', (id) => {
Trade.getInventory(config.bots[id].steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('bot inv', { error: err, items: data })
resolve();
})
})
})
var promise2 = new Promsie((resolve, reject) => {
socket.on('get user inv', (steamID64) => {
Trade.getInventory(steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('user inv', { error: err, items: data })
resolve();
})
})
})
If you want to wait until one finishes
promise1.then(() => {return promise2});
If you want N things to execute and await all of them, use the following
Promise.all([promise1, promise2]).then(() => {execute something else});
For further documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

You might want to use promises. At first, encapsulate the socket listeners and the API call with promises:
const getUserId = new Promise(res => socket.on('get bot inv', res));
const getBotId = new Promise(res => socket.on('get bot inv', res));
function getInventory(id) {
return new Promise((res, rej) => {
Trade.getInventory(id, config.appID, config.contextID, (err, data) => {
if(err) rej(err) else res(data);
});
}
Then its easy to chain the promises:
(async function() {
const userID = await getUserId;
const data = await getInventory(userID);
socket.emit({ data });
const botID = await getBotId;
const botData = await getInventory(config.bots[botID].steamID64);
socket.emit({ botData });
})();

Related

Getting PostgresSQL 42703 error (invalid column error)

I am working on a React project with PostgreSQL database, this is the first time I am using it, and I am getting 42703 error on querying a particular column.
Below is the code I have written to query
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id=${userId}`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
I have defined this getList function and then I am making an api call to call this function by passing the userId like this
app.get(`/expenses`, verifySession(), async (req, res) => {
const userId = req.session.userId;
database.getList(userId)
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
I even tried passing the userId directly as shown below , still it gives me the same error , which probably means I am querying in a wrong way
app.get(`/expenses`, verifySession(), async (req, res) => {
//const userId = req.session.userId;
database.getList('17a6dea6-a63e-4da7-9910-df7eddb672e6')
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
Only when I directly write the string in the query it works properly like this
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id='17a6dea6-a63e-4da7-9910-df7eddb672e6'`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
Can someone please help we with what is exactly going wrong and if my syntax is correct or not ?
This is the frontend part of where I am calling the api.
function getDataForUser() {
fetch(`http://localhost:3001/data`)
.then(response => {
return response.json();
}).then(data => {
console.log(data.rows[0]);
})
}
This problem happened because you didn't use a single quotation for string type in the query. When using where id=${userId} and called with 17a6dea6-a63e-4da7-9910-df7eddb672e6 converted to where id=17a6dea6-a63e-4da7-9910-df7eddb672e6 and this make problem.
You can use two scenarios to handle it:
Use the single quotation for string type:
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id='${userId}'`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
Use parameter binding (As default it converted type)
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id=$1`, [userId], (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}

Try to calculate 2 values from callback (Binance Api using JavaScript)

I have 2 different code to get data:
first is to get by balance account
the second is to get the current value of the coin
I need to calculate the number of coins that I can buy with the balance
(Balance*coin value = quantity)
I have tried many options to get the value outside of the function without luck.
first code: (get balance)
binance.balance((error, balances) => {
if ( error ) return console.error(error);
console.info("BTT balance: ", balances.BTT.available);
});
Second code (get coin value)
binance.prices('BTTUSDT',(error, ticker)=>{
console.info("Hello:: ", ticker.BTTUSDT);
});
Dive in callback hell:
binance.balance((error, balances) => {
if ( error ) return console.error(error);
console.info("BTT balance: ", balances.BTT.available);
binance.prices('BTTUSDT',(error, ticker)=>{
if ( error ) return console.error(error);
// Balance*coin
});
});
Or use Promises:
const getBalance = () => new Promise((resolve, reject) => {
binance.balance((error, balances) => {
if(error) {
reject(error);
return;
}
resolve(balances.BTT.available);
});
const getCoins = () => new Promise((resolve, reject) => {
binance.prices('BTTUSDT', (error, ticker) => {
if(error) {
reject(error);
return;
}
resolve(ticker.BTTUSDT);
});
(async () => {
const balance = await getBalance();
const coins = await getCoins();
console.info(balance * coins);
})();

Trying to refactor a promisified function in to try-catch block

I am trying to refactor this code using try-catch blocks:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
}).catch(error => console.log(error));
}
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
}).catch(error => console.log(error));
}
However I'm not getting the same result - the asynchronousity seems to be being handled differently. Here is my attempt at refactoring:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
try {
ConnectyCube.login(userCredentials, (error, user) => {
return user;
})
}
catch (error) {
console.log(error)
}
}
const createSession = () => {
try {
ConnectyCube.createSession((error, session) => {
return session.user
})
} catch (error) {
console.log(error);
}
}
Is there any particular part of what I'm wrong? Thanks.
Callback-based APIs don't readily turn into something you can use for async/await (which under the hood uses promises). You'll have to "promisify" them first (i.e. wrap them in promises).
Here's an example of what I'm trying to say:
// Promisify these callback-based APIs.
const login = userCredentials => {
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
})
})
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
})
})
// Then use them in an async function
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
}
try {
await createSession()
return login(userCredentials)
} catch (e) {
console.warn(e)
}
}
Also, async functions return promises, with the resolved value being the return value, and the rejected value being any uncaught error thrown inside. A value wrapped in a promise as return value for an async function is redundant.
If you're using Node 8+, it has a utility called promisify which accepts a callback-based API and returns a promise-returning version of it.

Code works from project but not from a Firestore Cloud Function

Update: Refactored the code at the end below to this:
let getMembersIDs = eventID => {
return admin.firestore().collection('events').doc(eventID).get()
.then(doc => {
if (doc.exists) {
console.log(doc.data().members)
return doc.data().members
}
else throw new Error ('Event does not exist!', doc.id)
})
}
let dispatchToMembers = (arrayMembersIDs, data) => {
return Promise.all(
arrayMembersIDs.map(memberID => {
if (data.at===memberID) data.type = 'pm'
else data.content = 'New message in an event chat you participate to.'
console.log('Sending now to: ', memberID)
return admin.firestore().collection('users').doc(memberID).collection('inbox').add({
content: 'You were mentioned in a recent chat: ' + data.content,
type: data.type
})
})
)
}
getMembersIDs(data.target).then(members => dispatchToMembers(members, data)).then(() => {
console.log('Message dispatched!')
res.end()
return true
})
.catch(err => {
console.error(err);
response.status(500).send(err);
return true;
})
})
It does work when I run it from my project, replacing admin.firestore() with db. However when embedded within a cloud function it does not work: the cloud function returns codes 204 and 200 but the desired db operation does not seem to occur. Pulling my hair as I don't understand why.
Outdate: I am not able to debug the following piece of code. A simple cloud function with two parts (a read, a write) chained with promises.
exports.discuss = functions.https.onCall((data, context) => {
return admin.firestore().collection('events').doc(data.target).get()
.then(doc => {
if (doc.exists) return doc.data().members
else throw new Error ('Doc does not exist ', doc.id)
})
.then(members => {
let promises = []
members.forEach(u => {
...
let promise = new Promise(res => {
admin.firestore().collection('users').doc(u).collection('inbox').add({...})
res(u)
})
promises.push(promise)
})
return Promise.all(promises)
})
.then(() => {
response.send('ok')
return;
})
.catch(err, response.status(500).send(err))
})
You generate that 500 code with this line:
.catch(err, response.status(500).send(err))
The client that invokes the Cloud Function should be getting the error message in the response body. But you'll also want to log it on the server with:
.catch(function(err) {
console.error(err);
response.status(500).send(err);
return true;
})

JavaScript: Promise.all returning undefined

I'm trying to create a user account creation script with a focus on unique usernames - a prefix and a suffix from a pool, a list of existing usernames, and a list of reserved usernames.
That's just the start of it (no saving yet!), and already that would require three connections, so I just decided to see if I can code a function that would handle them all.
Here's my code so far - and it's on AWS Lambda, and tested via API Gateway, if that means anything:
const dbConnMysql = require('./dbController');
var methods = {
createUser: function() {
let getPrefixSuffixList = new Promise((resolve, reject) => {
let connection = dbConnMysql.createConnection();
dbConnMysql.startConnection(connection)
.then((fulfilled) => {
let table = 'userNamePool';
return dbConnMysql.selectFrom(connection, table, '*', null);
})
.then((fulfilled) => {
console.log(fulfilled);
return dbConnMysql.closeConnection(connection)
.then((fulfilled) => {
resolve(fulfilled);
});
})
.catch((error) => {
console.log(error);
reject(error);
});
});
let getTempUserNameList = new Promise((resolve, reject) => {
// Same as getPrefixSuffixList, different table
});
let getRealUserNameList = new Promise((resolve, reject) => {
// Same as getPrefixSuffixList, different table
});
return new Promise((resolve, reject) => {
Promise.all([getPrefixSuffixList, getTempUserNameList, getRealUserNameList])
.then((fulfilled) => {
console.log(fulfilled[0]);
console.log(fulfilled[1]);
console.log(fulfilled[2]);
let response = {
"statusCode": 200,
"headers": {"my_header": "my_value"},
"body": {"Prefix Suffix":fulfilled[0], "Temp UserName List":fulfilled[1], "Real UserName List":fulfilled[2]},
"isBase64Encoded": false
};
resolve(response);
})
.catch((error) => {
let response = {
"statusCode": 404,
"headers": {"my_header": "my_value"},
"body": JSON.stringify(error),
"isBase64Encoded": false
};
reject(response);
})
});
}
};
module.exports = methods;
This function is called elsewhere, from index.js:
app.get('/createUserName', function (req, res) {
var prom = Register.createUser();
prom.then((message) => {
res.status(201).json(message);
})
.catch((message) => {
res.status(400).json(message);
});
})
Now I'm not entirely sure if what I did with the Promise.All is correct, but from what little I know, if one promise fails, the Promise.All fails.
However, the individual promises do work just fine, and log out the respective results from the database. But inside the Promise.All, it all just logs out undefined.
Is there something I'm missing?
The cause of your problem is this. You need to run the functions, these then return the promise that will eventually resolve:
Promise.all([getPrefixSuffixList(), getTempUserNameList(), getRealUserNameList()])
Here is some simpler code as well. In general there is no need for new Promise(). This code may fix other issues. Also, the undefined could be being printed from any part of the code, make sure it's being printed where you think it is.
// Dummy MySQL connector
const dbConnMysql = {
createConnection: () => 'Connection',
startConnection: conn => new Promise(resolve => setTimeout(resolve, 100)),
selectFrom: (conn, t, q, n) =>
new Promise(resolve =>
setTimeout(() => {
console.log(`${conn}: SELECT ${q} FROM ${t}`);
resolve(`x ${t} RECORDS`);
}, 100)
),
closeConnection: conn => new Promise(resolve => setTimeout(resolve, 100)),
};
const methods = {
createUser() {
const getPrefixSuffixList = () => {
const connection = dbConnMysql.createConnection();
return dbConnMysql
.startConnection(connection)
.then(() => {
const table = 'userNamePool';
return dbConnMysql.selectFrom(connection, table, '*', null);
})
.then(fulfilled => {
console.log(fulfilled);
return dbConnMysql.closeConnection(connection).then(() => fulfilled);
})
.catch(error => {
console.log(error);
// Note: this catch will stop the error from propagating
// higher, it could also be the cause of your problem.
// It's okay to catch, but if you want the error to
// propagate further throw a new error here. Like this:
throw new Error(error);
});
};
const getTempUserNameList = () => {
// Same as getPrefixSuffixList, different table
};
const getRealUserNameList = () => {
// Same as getPrefixSuffixList, different table
};
return Promise.all([getPrefixSuffixList(), getTempUserNameList(), getRealUserNameList()])
.then(fulfilled => {
console.log('fulfilled[0]: ', fulfilled[0]);
console.log('fulfilled[1]: ', fulfilled[1]);
console.log('fulfilled[2]: ', fulfilled[2]);
return {
statusCode: 200,
headers: { my_header: 'my_value' },
body: {
'Prefix Suffix': fulfilled[0],
'Temp UserName List': fulfilled[1],
'Real UserName List': fulfilled[2],
},
isBase64Encoded: false,
};
})
.catch(error => ({
statusCode: 404,
headers: { my_header: 'my_value' },
body: JSON.stringify(error),
isBase64Encoded: false,
}));
},
};
methods.createUser();

Categories