I've been struggling with the asynchronous nature of javascript in this project for a while now.
There are a lot of similar questions on this topic, but I feel they are all slightly different and have made it difficult for me to get a working solution.
I've been trying to create an api with these methods.
I started writing all my methods with callbacks which was okay while it was simple. But now it's causing me issues. So I've written some wrappers with util.promisify which has worked great.
I have this audit method which works perfectly.
const audit = (req, res, next) => {
Domains.audit(req.params.url)
.then((data) => {
res.json(data);
})
.catch((err) => {
res.json(err);
})
};
It returns this object which is planned to be assigned to "messages"
{
"warnings": [
"This url 301 redirects to https://www.google.com. Please update your entry."
],
"errors": []
}
Here's the problem.
I'm struggling to implement the auditAll method. I've tried using callbacks and promises, but it always returns before my audit calls modify the "report" I return
Here's some pseudocode of what I keep failing to create
auditAll(callback) {
// Get all domains with getAll() and make them look like this
report = {
'123' : {
'url' : 'https://google.com',
'other_props' : '...'
}
'124' : {
'url' : 'https://google2.com',
'other_props' : '...'
}
};
// For each report item
// run an audit which returns a message object
// assign that to it's spot in the report
report[item_key][messages] = audit(item.url)
// Report returns to the browser before the audits finish with every solution I've implemented.
// They send to my console like 50ms later.
callback(report)
}
Your audit() function would need to actually return the Promise it's creating...
const audit = (req, res, next) => {
return Domains.audit(req.params.url)
.then((data) => {
res.json(data);
})
.catch((err) => {
res.json(err);
})
};
... and then your auditAll() method needs to wait for all the audit() calls to finish. Since it looks like you're calling audit() once for each item in your report array, that could look something like this, using Array.map() and Promise.all():
Promise.all(
Object.values(report).map(
item => audit(item.url).then(
message => item[messages] = message
)
)
).then(() => callback(report));
Addendum: actually, there is some lack of clarity in your question - auditAll calls "audit(url)", but you've provided code for "audit(req, res, next)", so I'm not sure how those are related. The idea here is that audit() should be returning the promise of a message
audit(url) { return someAsyncFunc(url).then(() => message); }
which can then be used as I've described.