I am trying to perform SQL queries based on the callback results in if conditions but I am unable to write the code. So can somebody please provide some information how to do this with async/callback methods?
app.get('/resell-property', function(req, res) {
var data = {}
data.unit_price_id = 1;
function callback(error, result) {
if (result.count == 0) {
return hp_property_sell_request.create(data)
} else if (result.count > 0) {
return hp_unit_price.findAll({
where: {
unit_price_id: data.unit_price_id,
hp_property_id: data.property_id,
hp_unit_details_id: data.unit_details_id
}
})
}
}
hp_property_sell_request.findAndCountAll({
where: {
unit_price_id: data.unit_price_id
}
}).then(function (result) {
if (result) {
callback(null, result);
}
});
});
How can I write the callbacks for this?
hp_property_sell_request.create(data) ,hp_unit_price.findAll({
where: {
unit_price_id: data.unit_price_id,
hp_property_id: data.property_id,
hp_unit_details_id: data.unit_details_id
}
})
After returning the result I want to handle callbacks and perform this query:
if (result.request_id) {
return hp_unit_price.findAll({
where: {
unit_price_id:result.unit_price_id,
hp_property_id:result.property_id,
hp_unit_details_id:result.unit_details_id
}
}).then(function(result) {
if (result.is_resale_unit==0 && result.sold_out==0) {
return Sequelize.query('UPDATE hp_unit_price SET resale_unit_status=1 WHERE hp_unit_details_id='+result.unit_details_id+' and hp_property_id='+result.property_id)
}
})
}
Your question is too vague to answer precisely. I am assuming you need to call two methods and the latter should be called after the first method is completed and you need the results from the first method available in second methods.
Now, to the solution
Please note that callback and promise are very different approaches. It is very wise to stick with only one and not to mix callbacks and promises.
For your requirement, I highly recommend promises to avoid
callback hell.
Using callbacks, the solution looks something like
app.get('/resell-property', function(req, res) {
method1(req.body.id,function(err,result){
return method2(result);
})
function method1(input1,callback(err,result)){
try{
var result=st.execute("query");
return callback(null,result)
}catch(error){
return callback(error,null);
}
}
function method2(input2){
return input2;
}
})
Related
(I'm a beginner in JavaScript and have doubts in understanding javascript)
What my functions does?
Used Axios to get request and response from api in all three methods and log the status
This is implemented in three variants (callback,closure,promise)
My Understanding:
Legibility and readability is better in the below order:
Promise > Closures > Callback
//Callback
onMakeApiCallback() {
this.getData((response) => {
console.log("data callback success", response)
}, (error) => {
console.log("error is", error)
})
}
getData(onApiSuccess, onApiFail) {
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(function(response,error) {
if(response.data[3].title === "Red") {
onApiSuccess(response)
} else {
onApiFail(error)
}
})
}
The above is done using callback where i have sent a function as parameter to another function. I found this method to be complex when compared to other two.
//Closure
onMakeApiClosure() {
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(function(response,error) {
function innerfunction(response,error) {
if(response) {
console.log("success")
} else {
console.log("fail",error)
}
}
return innerfunction(response,error)
})
}
The above is done using Closure.Function within a Function
// Promise
onMakeApiPromise() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(function(response,error) {
console.log("1", response.data[3].title)
if(response.data[3].title === "Red") {
console.log("data is success", response)
} else if(error) {
console.log("error is ", error)
} else {
console.log("not equal")
}
})
}
When to use what?
Is there any other difference related to performance or any other traits among these three?
Links to understand
Closures
Callbacks
Promises
to understand promises u need to first get grip of asynchronous js.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am a newbie in JavaScript and I am a bit stuck with the async way JS executes code...
Here is my code :
var marketPlaces = []
body.rows.forEach(function(doc) {
marketPlacesDB.get(doc.id, function(err, body){
if (err) {
callback(err, null)
} else {
console.log("Ajout d'une marketplace")
marketPlaces.push({id: body._id, name: body.name})
}
})
})
console.log("Retour des résultats")
callback(null, { marketPlaces: marketPlaces })
body.rows is an array containing ids of objects I would like to return in the marketPlaces array. For each element, I need to make a new request to the database to get the details of the objects (here only the "name").
The result is an empty array because the foreach loop ends before the callbacks of the get function return.
I can't figure out how to make this "synchronous".
Thanks for your answers.
Philippe.
If they didn't give you the synchronous API, you can't.
But you can still make it works 'synchronous' by adding a big callback. (I'm a non-native English speaker, dunno what word should I use here)
let counter = 0;
const max = marketPlacesDB.getLength(); // base on the real situation
function regularCallback() {
/* your callback */
if(++counter == max)
bigCallback();
};
function bigCallback() {
// continue on your original work
}
You can't make it synchronous if marketPlaceDb is not providing api. But you can make it work with asynchronous version too:
var async = require('async')
function getMarketPlaces(callback) {
var marketPlaces = []
async.eachSeries(body.rows, doc, function (next) {
marketPlacesDB.get(doc.id, function(err, body){
if (err) {
next(err, null) // finish async operation
} else {
marketPlaces.push({id: body._id, name: body.name})
next() // go next iteration
}
})
}, function (err) {
// eachSeries done
// here is marketPlaces
console.log("Retour des résultats")
callback(err, { marketPlaces: marketPlaces })
})
}
getMarketPlaces(console.log)
I used 'async' library from npm and eachSeries method to iterate array asynchronously.
Thanks to Ozgur using async library seems to be the most elegant way to answer my question.
The correct code is :
var marketPlaces = []
async.eachOfSeries(body.rows, function (item, key, next) {
marketPlacesDB.get(item.id, function(err, body){
if (err) {
next(err, null)
} else {
marketPlaces.push({id: body._id, name: body.name})
next()
}
})
}, function (err) {
console.log("Retour des résultats")
callback(err, { marketPlaces: marketPlaces })
})
I have the following code:
const request = require('request-promise');
request(validateEmailOptions).then(function(result) {
if (result.valid) {
request(createUserOptions).then(function (response) {
if (response.updatePassword) {
request(modifyUserOptions).then(function (response) {
return res.redirect('/signin');
}).catch(function(error) {
return res.redirect('/error');
});
}
}).catch(function(error) {
return res.redirect('/error');
});
} else {
return res.redirect('/error');
}
})
.catch(function (reason) {
return res.redirect('/error');
});
Basically, it's a chain of request call, each one based on the result of the previous call. The problem is that I have many more lines in each condition and as a result, my code is bloated and hard to read and follow. I want to know if there is a better way to write the call chain using request-promises or simply request and bluebird.
You can unnest the promises. Think that this:
f(a).then(function(a) {
return g(b).then(function(b) {
return h(c)
})
})
Is the same as:
f(a).then(function(a) {
return g(b)
}).then(function(b) {
return h(c)
})
I would recommend failing as early as possible, that means handling the error condition first, and having meaningful error messages to be able to log them if need be. Finally, you can propagate the error and handle it in a single catch. To put it in context in your code:
request(validateEmailOptions).then(function(result) {
if (!result.valid) {
throw new Error('Result is not valid');
}
return request(createUserOptions);
}).then(function(response) {
if (!response.updatePassword) {
throw new Error('Password is not updated');
}
return request(modifyUserOptions);
}).then(function(response) {
return res.redirect('/signin');
}).catch(function(error) {
// you may want to log the error here
return res.redirect('/error');
});
I'm using a function which returns data in a paginated form. So it'll return max 100 items and a key to retrieve the next 100 items. I want to retrieve all the items available.
How do I recursively achieve this? Is recursion a good choice here? Can I do it any other way without recursion?
I'm using Bluebird 3x as the promises library.
Here is a snippet of what I'm trying to achieve:
getEndpoints(null, platformApplication)
.then(function(allEndpoints) {
// process on allEndpoints
});
function getEndpoints(nextToken, platformApplication) {
var params = {
PlatformApplicationArn: platformApplication
};
if (nextToken) {
params.NextToken = nextToken;
}
return sns.listEndpointsByPlatformApplicationAsync(params)
.then(function(data) {
if (data.NextToken) {
// There is more data available that I want to retrieve.
// But the problem here is that getEndpoints return a promise
// and not the array. How do I chain this here so that
// in the end I get an array of all the endpoints concatenated.
var moreEndpoints = getEndpoints(data.NextToken, platformApplication);
moreEndpoints.push.apply(data.Endpoints, moreEndpoints);
}
return data.Endpoints;
});
}
But the problem is that if there is more data to be retrieved (see if (data.NextToken) { ... }), how do I chain the promises up so that in the end I get the list of all endpoints etc.
Recursion is probably the easiest way to get all the endpoints.
function getAllEndpoints(platformApplication) {
return getEndpoints(null, platformApplication);
}
function getEndpoints(nextToken, platformApplication, endpoints = []) {
var params = {
PlatformApplicationArn: platformApplication
};
if (nextToken) {
params.NextToken = nextToken;
}
return sns.listEndpointsByPlatformApplicationAsync(params)
.then(function(data) {
endpoints.push.apply(endpoints, data.Endpoints);
if (data.NextToken) {
return getEndpoints(data.NextToken, platformApplication, endpoints);
} else {
return endpoints;
}
});
}
For a more general purpose example of recursively getting and returning data from a paginated endpoint, here is what I came up with:
getData(page, dataArray) {
return new Promise((resolve, reject) => {
getEndpointHere(
{
page,
pageSize: 50,
},
(err, result) => {
if (err)
return console.error("there was a problem retrieving your data");
dataArray = dataArray.concat(result);
if (result.length < 50) {
resolve(dataArray);
} else {
resolve(getData(page + 1, dataArray));
}
}
);
});
}
getData(1, [])
.then((res) => {
console.log("SEVERAL PAGES OF DATA", res);
})
This example is employing a callback -- (err, result) -- however, that logic could be extracted out to handle the response from the endpoint. The resource I was consuming does not return a cursor or "next" token indicating if there are more records, so I used the logic of if the response has less than 50 records as the basis for continuing to request more data.
I keep running into this pattern when coding in Meteor where I find myself making multiple method calls nested within each other - first method fires, then in the callback, a second one fires which is dependent on the first one's result, etc. Is there a better pattern for using multiple methods without nested method calls inside callbacks? The code quickly gets messy.
Meteor.call('unsetProduct', product._id, omitObj, function(err, result) {
if(!err) {
Meteor.call('editProduct', product._id, object, function(err, result) {
if(!err) {
//if no error, then continue to update the product template
Meteor.call('editProductTemplate', self._id, obj, function(err, result) {
if(!err) {
//call some other method
}
else {
FormMessages.throw(err.reason, 'danger');
}
});
}
else {
FormMessages.throw(err.reason, 'danger');
}
});//end edit product
}
else {
AppMessages.throw(err.reason, 'danger');
}
});`
Take a look at reactive-method package. I think it does exactly what you need: it wraps asynchronous Meteor.calls into synchronous code. With it, your code would look cleaner, like
try {
const result = ReactiveMethod.call('unsetProduct', product._id, omitObj);
} catch (error) {
AppMessages.throw(err.reason, 'danger');
}
try {
const nestedResult = ReactiveMethod.call('editProduct', product._id, object);
} catch (error) {
FormMessages.throw(err.reason, 'danger');
}
try {
const evenMoreNestedResult = ReactiveMethod.call('editProductTemplate', self._id, obj);
} catch (error) {
FormMessages.throw(err.reason, 'danger');
}
Which will look nicer when you add some logic inside try statements.