I am new to promises and trying to figure out for quite a long time now how to get proper results after the usage of a async network call with which I receive data.
I receive my balance from a exchange and loop through several parameters. When this is finished the holdings should be returned.
However, I still have to fight the async behaviour. When I run the code without the commented code, the result is []. If I set a artificial setTimeout, then the returned array holdings is visible properly.
Can someone tell me please where my mistake lays? I tried to read through docs of mdn and similar problems here on stackoverflow but I am nonetheless stuck.
Thank you guys very much,
Tobias
const bittrex = require('node.bittrex.api');
const {key, secret} = require('./key')
let getBalance = new Promise((resolve, reject) => {
let holdings = [];
bittrex.getbalances( function( data, err ) {
if (err) {
reject(err);
}
data.result.forEach(coin => {
if (coin.Balance !== 0) {
let market = `BTC-${coin.Currency}`;
if(coin.Currency === 'BTC') market = `USDT-BTC`;
bittrex.getticker( { market : market}, function( ticker, err ) {
if (err) {
reject(err);
}
holdings.push({
Coin: coin.Currency,
Balance: coin.Balance,
Last: ticker.result.Last
});
})
}
});
});
resolve(holdings);
})
getBalance
// .then((holdings) =>{
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(holdings);
// }, 10000)
// })
// })
.then((holdings) => {
console.log(holdings);
})
You're resolving your promise instantaneously but the data is not here yet, as it is happened asynchronously during the callback. Your promise should be resolved after every callback.
What you should do is create a promise for each of the request and then resolve your function with a Promise.all
const bittrex = require('node.bittrex.api');
const {key, secret} = require('./key')
let getBalance = new Promise((resolve, reject) => {
let holdings = [];
bittrex.getbalances( function( data, err ) {
if (err) {
reject(err);
}
const promises = data.result.map(coin => new Promise((resolve, reject) => {
if (coin.Balance !== 0) {
let market = `BTC-${coin.Currency}`;
if(coin.Currency === 'BTC') market = `USDT-BTC`;
bittrex.getticker( { market : market}, function( ticker, err ) {
if (err) {
reject(err);
}
resolve({
Coin: coin.Currency,
Balance: coin.Balance,
Last: ticker.result.Last
});
})
}
});
resolve(Promise.all(promises));
});
});
Your getBalance promise will be resolved when all of your promise are resolved. Be cautious though, if one of your promise is rejected, then the whole promise will be rejected.
If it's properly resolved, then the value will be an array of each value of the promises.
Since I'm assuming bittrex.getticker is async, you should instead just wrap each call into a promise and not try to combine them into one manually.
Here's a loose concept.
function getTicker(...) {
return new Promise(function(resolve, reject) {
bittrex.getticker(..., function(ticker, error) {
if (error) { reject(error); }
else { resolve(ticker); }
});
});
}
var lotsOfPromises = data.result.map(function(coin) {
return getTicker(...).then(function(ticker) {
return { yourOutputdata }
});
});
Promise.all(lotsOfPromises);
Related
Here is a function to find mx records of a service and i need to save the one value(with the lowest priority) to make a request to it. How can I save and return this value?
const dns = require('dns');
const email = '...#gmail.com'
let res = email.split('#').pop();
function getMxRecords(domain) {
return new Promise(function(resolve, reject) {
dns.resolveMx(domain, function(err, addresses) {
if (err) {
//console.log(err, err.stack)
resolve(null);
} else {
//console.log(addresses);
let copy = [...addresses];
//console.log(copy);
let theone = copy.reduce((previous, current) => {
if (previous.priority < current.priority) {
return current;
}
return previous;
});
resolve(theone);
}
});
});
}
let a = getMxRecords(res);
console.log(a);
Yeah, so i need to export this module to make a request to it like below;
let socket = net.createConnection(25, request(email), () => {})
so for this my function should request me or array or object with only one value, when i'm trying it doesn't work, i always get this:
Promise { } //HERE IS RETURN FROM MY FUNCTION (WITH .THEN)
Error in socket connect ECONNREFUSED 127.0.0.1:25
A Promise is mostly an asynchronous call. It returns an Promise-Object that will resolve or reject the Promise. To access the result, you will call some functions:
function getMxRecords(domain) {
return new Promise(function(resolve, reject) {
dns.resolveMx(domain, function(err, addresses) {
if (err) {
//console.log(err, err.stack)
resolve(null);
} else {
//console.log(addresses);
let copy = [...addresses];
//console.log(copy);
let theone = copy.reduce((previous, current) => {
if (previous.priority < current.priority) {
return current;
}
return previous;
});
resolve(theone);
}
});
});
}
getMxRecords(res)
.then(yourResolveValueProvided => {
// Your code if the promise succeeded
})
.catch(error => {
// Your code if the promises reject() were called. error would be the provided parameter.
})
I want to save sqlite3 row values into an array. I followed what was discussed here:
Can't put rows into array using sqlite3 on Node.js
However when I console.log my would-be-array records, I obtain:
console.log(records) => an array with values [1,1,2]
console.log(records[1]) => undefined
There must be a mistake in my understanding of what's going on. What is wrong?
Full code below:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('src/db/ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let records = [];
function catchResult (err, row)
{
if (err) { return console.log(err.message); }
else { return result.push(row.objektid); }
}
function getData ()
{
return new Promise ((resolve, reject) =>
{
db.parallelize ( () =>
{
db.each(sqlTitel(param), catchResult);
db.each(sqlAutor(param), catchResult);
});
resolve(result);
})
}
async function res ()
{
records = await getData();
console.log(records);
console.log(records[1]);
return records;
};
let x = res();
console.log(x);
The contradiction between console.log(records) and console.log(records[1]) does not exist in the commandline. It seems that some other code interferes in the console.
Moreover, the promise as implemented above resolves with the emtpy result-array before the database request is finished. One can introduce a timeout to play with the code.
In order to resolve the promise after the database request, one should resolve it in the callback function of the request. That's also the reason why db.all is much easier to handle than db.each.
Instead of a series of database requests one can then use a series of promises. Thereby it is important to wait for every single promise to be resolved (just coupling them like this return await sqr(sqlTitle(y), []).then(sqr(sqlAuthor(y), [])) gives no unique result). The result-array is completed bit by bit.
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let p;
function sqr (sql, x)
{
return new Promise(function (resolve, reject)
{
db.all(sql, x, (err, rows) =>
{
if (err) {
reject(err);
} else {
rows.forEach( (row) => {result.push(row.objektid)} );
resolve(result);
}
});
});
}
( async () =>
{
p = await sqr(sqlTitle(y), []);
p = await sqr(sqlAuthor(y), []);
return p; //the final result
})();
I have two functions that return promise. The first one provide host value, and the second one use the host value to get IP address. I can see that the first function is running without any issue. But looks like the callback function side getHostIps is not executed at all. Not sure why it happens....what's wrong with my promise function?
my promise chain:
getHostedZoneId(dns)
.then(hostZoneId => {
getHostIps(dns, hostZoneId);
})
.then(hostIps => {
logger.Info(hostIps); //hostIps is undefined
})
.catch(err => logger.error(err));
getHostedZoneId:
var getHostedZoneId = function(dns) {
var params = {
DNSName: dns,
};
return new Promise((resolve, reject) => {
findHostZoneByDNS(params, function(err, data) {
if(err) {
reject(err);
}
else {
resolve(data);
}
});
});
}
getHostIps:
var getHostIps = function(dns, hostZoneId) {
var params = {
HostedZoneId: hostZoneId,
StartRecordName: dns,
};
return new Promise((resolve, reject) => {
findHostIps(params, function(err, data) {
//logger.info("get there");
if(err) {
reject(err);
}
else {
resolve(data);
}
});
});
}
I logged hostIps and err and data, all of them are defined. So I am sure that the callback function inside promise is not executed. But not sure how to fix it.
Any feedback is appreciated! Thanks!
You have to return the promise from your then statement to complete the chain.
getHostedZoneId(dns)
.then(hostZoneId => {
return getHostIps(dns, hostZoneId); // Add return
})
.then(hostIps => {
logger.Info(hostIps);
})
.catch(err => logger.error(err));
I have a situation where I think the only choice for me is to nest some Promises within each other. I have a Promise that needs to be performed and a method that does something until that Promise is complete. Something like this:
let promise = new Promise((resolve, reject) => {
// Do some stuff
});
doSomethingUntilPromiseisDone(promise);
However, within my Promise, I need to execute another method that returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
// Do something here
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
But now, in the fetchValue method's then statement, I have another method I need to execute that, guess what, returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
saveToCache(value)
.then((success) => {
console.log('success!!');
resolve('success');
});
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
So in the end, I have a Promise, within a Promise, within a Promise. Is there someway I can structure this better so that it is more straightforward? It seems like nesting them within each other is counter to Promise's intended chaining approach.
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
you can use generator to flatten your nested promises (Bluebird.couroutine or Generators)
//Bluebird.couroutine
const generator = Promise.coroutine(function*() {
try {
const value = yield fetchValue(url);
const success = yield saveToCache(value);
console.log('success:', success);
} catch(e) {
console.error(err);
}
}));
generator();
Each function will call the next one with the result of the method before.
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);
Why does this series of promises run out of order? The "object" object in the final .then block is undefined at runtime.
new Promise(function(resolve, reject) {
getConnection().query("SELECT * FROM blog", (err, rows) => {
if (err) reject(err)
else resolve(rows)
})
}).then(rows => {
let posts = []
for (let i = 0; i < rows.length; i++) {
posts.push({
id: rows[i].id,
...
})
}
return posts
}).then(posts => {
getConnection().query("SELECT * FROM shows", (err, rows) => {
if (err) throw new Error(err)
else return { posts: posts, shows: rows }
})
}).then(object => {
let posts = object.posts
let post_container = { my: [], your: [] }
post_container.my = posts.filter(x => x.section === "my")
post_container.your = posts.filter(x => x.section === "your")
return post_container
})
Your return in
.then(posts => {
getConnection().query("SELECT * FROM shows", (err, rows) => {
if (err) throw new Error(err)
else return { posts: posts, shows: rows }
})
})
...returns from the query callback, not the then callback; that return value is completely ignored. Since there's no explicit return in the then callback, it returns a promise resolved with undefined and so the following then callback is called with undefined (and before the async work above is done).
You need to return either a value to use immediately or a promise from the then callback; since your code in the then callback is asynchronous, you'll want to return a promise that you settle when the async work is complete, so:
.then(posts => {
return new Promise((resolve, reject) => {
getConnection().query("SELECT * FROM shows", (err, rows) => {
if (err) reject(/*...reject reason...*/)
else resolve({ posts: posts, shows: rows })
})
})
})
You might look at one of the libs that promise-ifies NodeJS callbacks so you can use promises more directly in your code. There are at least a couple, and then you could use the promise a promise-ified query gave you rather than having to create your own each time.