This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 9 months ago.
async function bringData() {
return new Promise(resolve => {
setTimeout(() => {
resolve(con.query('SELECT company, industry FROM my_table', function (err, result) {
if (err) {
console.error(err);
throw 'Error getting data from google_businesses table';
} else {
return result;
}
}));
}, 1000);
});
}
(async () => {
// return data from brindData function
let getData = await bringData();
console.log(getData);
})();
I am calling this function in main but I am always getting error. I am kind of new to node so if please anybody can guide me or is there any other way to do this such that when I have got my result I can return it.
Call resolve with the result from your query.The con.query looks like another asynchronous thing:
con.query('...', (err, result) => {
if (!err)
resolve(result);
});
You can try this.
async function bringData() {
return new Promise((resolve, reject) => {
con.query('SELECT company, industry FROM my_table', (err, result) => {
if (err) {
reject(err);
}
resolve(result);
})
});
}
(async () => {
// execute bringData function
try {
let getData = await bringData();
console.log(getData);
} catch (e) {
console.error(e);
}
})();
Edited with timeout
async function bringData() {
return new Promise((resolve, reject) => {
con.query('SELECT company, industry FROM my_table', (err, result) => {
if (err) {
reject(err);
}
resolve(result);
})
});
}
function timeout(seconds = 10) {
return new Promise(resolve => {
setTimeout(resolve, 10 * 1000)
})
}
(async () => {
// execute bringData function
try {
await timeout();
let getData = await bringData();
console.log(getData);
} catch (e) {
console.error(e);
}
})();
Related
I am trying to get the result of an async function in my calculateOrderAmount function but it returns undefined.
The console.log in the called function returns the good result, but inside calculateOrderAmount, I get undefined. Here is my code:
getMultiStrats = async () => {
await MultiStrats.findOne({}, (err, multiStrats) => {
if (err) {
return err
}
if(!multiStrats) {
return console.log('MultiStrat not found')
}
console.log('returns MultiStrat: ' + multiStrats)
return multiStrats
})
.catch(err => console.log(err))
}
async function calculateOrderAmount(balance, ticker){
const multiState = await StrategyController.getMultiStrats().catch((err) => console.log(err))
console.log('multiState: ' + multiState)
some logic
}
Here is the console log:
multiState: undefined
returns MultiStrat: {
_id: 5ff73c74d1135b39fc709b80,
positionsCount: 1,
inTradeCount: 0,
__v: 0
}
What did I miss? Thanks you very much for your time!
The current approach is pretty unclear--there's no need for .catch, async, await all at once. return multiStrats returns from the inside of the callback, not from getMultiStrats. The async/await on getMultiStrats is superfluous, just adding another promise wrapper that doesn't accomplish anything.
Given that findOne as shown here uses a callback rather than a promise, you can either use callbacks all the way or you can promisify findOne as follows, using .then and .catch in the caller:
const MultiStrats = {
findOne: (obj, cb) => cb(null, "I'm a multistrat!")
};
const StrategyController = {
getMultiStrats: () => new Promise((resolve, reject) =>
MultiStrats.findOne({}, (err, multiStrats) => {
if (err) {
return reject(err);
}
else if (multiStrats) {
return resolve(multiStrats);
}
reject(Error("Multistrat not found"));
})
)
};
const calculateOrderAmount = (balance, ticker) =>
StrategyController
.getMultiStrats()
.then(multiState => {
console.log('multiState: ' + multiState)
// some logic
})
.catch(err => console.error(err))
;
calculateOrderAmount();
Or use async/await and try/catch:
const MultiStrats = {
findOne: (obj, cb) => cb(null, "I'm a multistrat!")
};
const StrategyController = {
getMultiStrats: () => new Promise((resolve, reject) =>
MultiStrats.findOne({}, (err, multiStrats) => {
if (err) {
return reject(err);
}
else if (multiStrats) {
return resolve(multiStrats);
}
reject(Error("Multistrat not found"));
})
)
};
const calculateOrderAmount = async (balance, ticker) => {
try {
const multiState = await StrategyController.getMultiStrats();
console.log('multiState: ' + multiState)
// some logic
}
catch (err) {
console.error(err);
}
};
calculateOrderAmount();
If this is MongoDB's findOne and already returns a promise, then you can just return the promise to the caller, optionally awaiting it and throwing for the null result:
const MultiStrats = {
findOne: async query => "I'm a multistrat!"
};
const StrategyController = {
getMultiStrats: async () => {
const result = await MultiStrats.findOne({});
if (result) {
return result;
}
throw Error("Multistrat not found");
}
};
const calculateOrderAmount = (balance, ticker) =>
StrategyController
.getMultiStrats()
.then(multiState => {
console.log('multiState: ' + multiState);
// some logic
})
.catch(err => console.error(err))
;
calculateOrderAmount();
You cannot return values from an inner callback and reach the outer function, I would suggest
1- only use promises
2- wrap your code with promise to be sure that await will return the async result the way you expect to have.
getMultiStrats = async () => {
return new Promise((resolve, reject) => {
MultiStrats.findOne({}, (err, multiStrats) => {
if (err) {
return err
}
if (!multiStrats) {
console.log('MultiStrat not found')
reject('MultiStrat not found')
}
console.log('returns MultiStrat: ' + multiStrats)
resolve(multiStrats);
})
.catch(err => {
console.log(err);
reject(err)
})
})
}
async function calculateOrderAmount(balance, ticker) {
try {
const multiState = await StrategyController.getMultiStrats()
console.log('multiState: ' + multiState)
// some logic
} catch (error) {
console.error(error);
}
}
Assuming that you use mongoose. I suggest using the promise interface like described in the documentation.
const getMultiStrats = async () => {
const query = MultiStrats.findOne({});
let multiStrats;
try {
multiStrats = await query.exec();
} catch (error) {
return error;
}
if (multiStrats) {
console.log("returns MultiStrat: " + multiStrats);
} else {
console.log("MultiStrat not found");
}
return multiStrats;
}
I would personally not return the error, but instead just let the error be thrown. With the above code the caller of getMultiStrats has to figure out if there return value is the expected result or an error. If you don't catch the error, it is thrown further up to the caller.
const getMultiStrats = async () => {
const multiStrats = await MultiStrats.findOne({}).exec();
if (multiStrats) {
console.log("returns MultiStrat: " + multiStrats);
} else {
console.log("MultiStrat not found");
}
return multiStrats;
}
You can further simplify this if you where to leave the console.log of of the equation.
const getMultiStrats = () => MultiStrats.findOne({}).exec();
I'm trying to return the result from this function :
var YouTube = require('youtube-node');
var youTube = new YouTube();
youTube.setKey('XXXXXXXXXXXX');
var result = youTube.search('World War z Trailer', 2,
function(error, result) {
if (error) {
console.log(error);
} else {
return result
}})
console.log(result)
But then I only get undefined as a result in console.
You need to wait for the response.
This simple answer is to place the console.log(result) inside the callback.
Or you can wrap the search method in a promise:
var promise = new Promise((resolve, reject) => {
youTube.search('World War z Trailer', 2, function (error, result) {
if (error) {
reject(error);
}
else {
resolve(result);
}
})
});
Then you can wait for the response using .then() like this:
promise.then((result) => {
console.log(result);
}).catch((err) => {
console.error(err);
});
Or using await/async:
(async () => {
try {
const result = await promise;
console.log(result);
} catch (err) {
console.error(err)
}
})();
Last function here is a callback function, it doesn't return value in way you want. Read how it works somewhere, for example here.
Your issue could be resolved with Promise in this way
var search = new Promise(
(resolve, reject) => {
youTube.search('World War z Trailer', 2, function(error, result) {
if (error) { reject(error); }
resolve(result);
})
}
);
(async () => {
var result = await search;
console.log(result);
})()
I am using a library that calls an API, and I am waiting for Promise return to receive an Array.
However, even though I expect 2 elements in ActivityItem array, sometimes I receive only first of them (the one that appears first (Item1). From my point of view, I implemented the Promise incorrectly and there should be a mistake in the way I return them, but I miss seeing it.
Here I call the function that uses that should return Promise:
componentDidMount() {
this.getDataFromKit(ONEDAYINTERVAL).then(result => {
this.sendDataToServer(result); //sending to backend
}).catch(e => console.error);
}
And here is a method itself:
getDataFromKit(dateFrom) {
return new Promise((resolve) => {
AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
if (err) {
return;
}
AppleKit.getSamples(dateFrom, (err, results) => {
if (err) {
return resolve([]);
}
const newData = results.map(item => {
return { ...item, name: "Item1" };
});
const allData = [...this.state.ActivityItem, ...newData];
this.setState({ ActivityItem: allData });
resolve(allData);
});
// if I delete the code below it will work just fine always grabbing only one item.
new Promise((resolve) => {
AppleKit.getSamplesSecondMethod(dateFrom, (err, results) => {
if (err) {
return resolve([]);
}
const newData = results.map(item => {
return { ...item, name: "Item2" };
});
const allData = [...this.state.ActivityItem, ...newData];
this.setState({ ActivityItem: allData });
resolve(allData);
});
});
});
})
}
The main issue here is I guess: how can I return multiple promises from this one method?
The problem as I see it, is your second block of code doesn't get run because you are resolving the promise in the first block. The way you have it coded, you will want to resolve that promise only once all your async operations have completed. I modified your code, but have not tested it. It may need to add the .then method to make sure the async data is returned before resolving the initial promise.
What happens if you try this ?
UPDATE
It looks like the below code solved your problem as you accepted my answer. However, I did re-write it before I realized you accepted so I will add the new updated code in case that will help you or someone else.
Original Answer
getDataFromKit(dateFrom) {
const thenable = new Promise((resolve) => {
AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
if (err) {
return;
}
AppleKit.getSamples(dateFrom, (err, results) => {
if (err) {
return resolve([]);
}
const newData = results.map(item => {
return {
...item,
name: "Item1"
};
});
resolve(newData);
});
});
})
.then((newData) => {
AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
if (err) {
return;
}
AppleKit.getSamplesSecondMethod(dateFrom, (err, results) => {
if (err) {
return;
}
var stateData = this.state.ActivityItem;
const addData = results.map(item => {
return {
...item,
name: "Item2"
};
});
stateData = [...stateData, ...newData];
stateData = [...stateData, ...addData];
this.setState({
ActivityItem: stateData
});
});
});
});
return thenable;
}
Updated Code using Promise.all
getDataFromKit(dateFrom) {
return new Promise((resolve) => {
const promise1 = new Promise((resolve) => {
AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
if (err) {
return Promise.reject(err);
}
AppleKit.getSamples(dateFrom, (err, results) => {
if (err) {
return Promise.reject(err);
}
const newData = results.map(item => {
return {
...item,
name: "Item1"
};
});
return Promise.resolve(newData);
});
});
});
const promise2 = new Promise((resolve) => {
AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
if (err) {
return Promise.reject(err);
}
AppleKit.getSamplesSecondMethod(dateFrom, (err, results) => {
if (err) {
return Promise.reject(err);
}
const moreData = results.map(item => {
return {
...item,
name: "Item2"
};
});
return Promise.resolve(moreData);
});
});
});
Promise.all([promise1, promise2])
.then(([result1, result2]) => {
var nArrays = [result1, result2, this.state.ActivityItem];
const finalResult = [].concat(...nArrays);
return Promise.resolve(finalResult);
});
});
}
I would like to make an Ajax request to my MongoDB server and use the data along with other async tasks using a standalone function so that I can modularize my code as much as possible. I am not very experienced with async programming so I might be doing some basic mistake. In my code, I used another function (doubleAfter2Seconds) returning a promise, which works fine. The result variable from await getMongoData("mydb", url) is outputted as undefined instead of the actual data.
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://{MyServer}:27017/";
function getMongoData(dboArg, urlArg) {
var myPromise = () => {
return new Promise(resolve => {
MongoClient.connect(urlArg, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db(dboArg);
dbo.collection(myCollection).find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
resolve(result[0]);
});
})
})
}
}
function doubleAfter2Seconds(x) {
return new Promise(resolve => {
console.log("v");
setTimeout(() => {
resolve(x * 2);
}, 1000);
});
}
async function addAsync(x) {
// This works
const a = await doubleAfter2Seconds(10);
console.log(a);
// This doesn't work
result = await getMongoData("mydb", url);
console.log(result);
return x;
}
addAsync(10).then((sum) => {
console.log(sum);
});
Here is the corrected getMongoData function based on the comments
function getMongoData(dboArg, urlArg) {
return new Promise(resolve => {
MongoClient.connect(urlArg, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db(dboArg);
dbo.collection(myCollection).find({}).toArray(function(err, data) {
err
? reject(err)
: resolve(data[0]);
});
})
})
}
I want to execute four blocks of code sequentially and conduct test during this sequential execution. The challenge is that the blocks contain calls of asynchronous functions.
I cannot seem to wrap my head around promises to use them properly and I just seem stuck after spending several hours on the block of code.
// Store current log of drone visits for DJI Phantom 4
db.query("SELECT COUNT(drone_id) FROM Drone_Visits WHERE drone_id = 2;", function(err, rows) {
if (err) {
console.log(err);
}
else {
current_drone_visits = rows[0]['COUNT(drone_id)'];
}
});
it("should return status 200 (OK) when requesting route for this function", function(done) {
request.get("/product/DJI/Phantom_4").query({brand: dji_brand, model: dji_model}).end(function(err, res) {
assert.equal(res.status, 200);
done();
});
});
db.query("SELECT COUNT(drone_id) FROM Drone_Visits WHERE drone_id = 2;", function(err, rows) {
if (err) {
console.log(err);
}
else {
updated_drone_visits = rows[0]['COUNT(drone_id)'];
}
});
it("should increment the value of drones visited in the database", function(done) {
console.log("A - " + current_drone_visits);
console.log("B - " + updated_drone_visits);
assert.equal(current_drone_visits + 1, updated_drone_visits);
done();
});
What should I do here if I want to chain my callbacks such that they execute only after the previous function has finished?
Use async.js if you are comfortable with callbacks, or use Promises, you can chain them in order to synchronise you functions.
just wrap your callback in a function that return a promise like this
function P(){
return new Promise((resolve, reject)=>{
db.query("SELECT COUNT(drone_id) FROM Drone_Visits WHERE drone_id = 2;", function(err, rows) {
if (err) reject(err);
else {
resolve(rows[0]['COUNT(drone_id)'])
}
});
})
}
function T1(data){
//data in this case will be the result of the P() function
return new Promise((resolve, reject)=>{
request.get("/product/DJI/Phantom_4").query({brand: dji_brand, model: dji_model}).end(function(err, res) {
if(err || res.status==200) reject(err);
resolve();
});
})
}
P()
.then(T1)
.then(...)
.catch((err)=>{
//handle error here
})
sry for the bad formatting
What should I do here if I want to chain my callbacks such that they
execute only after the previous function has finished.
This code does it for you:
describe ('test', function () {
this.timeout(6000);
it ('test', function(done) {
var query1 = new Promise (function (resolve, reject) {
db.query("SELECT COUNT(drone_id) FROM Drone_Visits WHERE drone_id = 2;", function(err, rows) {
if (err) {
reject(new Error('rejected query1'));
} else {
var current_drone_visits = rows[0]['COUNT(drone_id)'];
resolve(current_drone_visits);
}
});
})
.then(function(current_drone_visits){
var request1 = new Promise (function (resolve, reject) {
request.get("/product/DJI/Phantom_4").query({brand: dji_brand, model: dji_model}).end(function(err, res) {
if (err) {
reject(new Error('rejected request'));
} else {
resolve(res);
}
})
})
.then(function (res) {
try {
assert.equal(res.status, 200);
return current_drone_visits;
}
catch (err) {
done (err);
}
})
.catch(function(err) {
return Promise.reject(err);
})
return request;
})
.then(function(current_drone_visits) {
var query2 = new Promise (function (resolve, reject) {
db.query("SELECT COUNT(drone_id) FROM Drone_Visits WHERE drone_id = 2;", function(err, rows) {
if (err) {
reject(new Error('rejected query2'))
} else {
resolve();
}
})
})
.then(function () {
var updated_drone_visits = rows[0]['COUNT(drone_id)'];
var bundled = [current_drone_visits, updated_drone_visits];
return bundled;
})
.catch(function(err) {
return Promise.reject(err);
})
return query2;
})
.then(function(bundled) {
var current_drone_visits = bundled[0];
var updated_drone_visits = bundled[1];
console.log('A - ' + current_drone_visits);
console.log('B - ' + updated_drone_visits);
assert.equal(current_drone_visits + 1, updated_drone_visits);
done()
})
.catch (function (err) {
done(err);
})
})
})
You can use the this.timeout(6000) to determine how long Mocha will wait for your asynchronous code to complete. The default value is 2000 ms which may or may not be sufficient in your case.