How to return value in promise javascript - javascript

I have some issue with my code. I need to return a value in promise but don't know how to achived that. I'm newbie in ECS6
Following is my createDate function:
var createData = function (i, object) {
return new Promise(function(resolve) {
var item = object[i]
handleDiease(item.disease).then(function (diseaseId) {
handleCountry(item.country).then(function (countryId) {
handleStatus(lodash.capitalize(item['status(no/failed attempt/yes/friend)'])).then(function (statusId) {
handleType(lodash.capitalize(item["type(o/p)"])).then(function (typeId) {
ContactBLL.create({
name: item.name,
organisation: item.organisation,
email: item.email,
phonenumbers: item.phone,
facebook_url: item.facebook_url,
contactdate: item.date,
da_name: item.donation_affiliate_name,
da_url: item.donation_affiliate_url,
article_url: item.article_url,
//isparticipatefacp: item.isparticipatefacp,
survey_id: item.survey,
notes: item.notes,
fbcontact_diseaseid: diseaseId,
fbcontact_countryid: countryId,
lk_contactstatusid: statusId,
lk_contacttypeid: typeId,
}).then(function (rs) {
if (i < object.length - 2) createData(i + 1, object)
else {
**In else case, i want to return value, i'm using resolve(true) or return true but bold of them not work**
}
});
})
})
})
})
})
}
Following is where I use createDate function:
createData(0, json).then(function(rs) {
console.log(rs)
**It not console anything because I think createData not return or resolve anything**
})

You need to chain your promises, each then should return the promise inside it. Also, avoid explicit construction:
var createData = function (i, object) {
var item = object[i]
var desease = handleDiease(item.disease); // make all requests
var country = handleCountry(item.country); // concurrently, no need to wait
var stat = handleStatus(lodash.capitalize(item['status(no/failed attempt/yes/friend)']));
var type = handleType(lodash.capitalize(item["type(o/p)"]))
// join aggregates several promises, notice the `return` here.
return Promise.join(desease, country, stat, type,
function(deseaseId, countryId, statusId, typeId) {
return ContactBLL.create({ // this needs a `return` too
name: item.name,
organisation: item.organisation,
email: item.email,
phonenumbers: item.phone,
facebook_url: item.facebook_url,
contactdate: item.date,
da_name: item.donation_affiliate_name,
da_url: item.donation_affiliate_url,
article_url: item.article_url,
//isparticipatefacp: item.isparticipatefacp,
survey_id: item.survey,
notes: item.notes,
fbcontact_diseaseid: diseaseId,
fbcontact_countryid: countryId,
lk_contactstatusid: statusId,
lk_contacttypeid: typeId,
});
})
.then(function (rs) { // chain the promise
if (i < rs.length - 2) return createData(i + 1, rs);
else return true;
});
};

Related

Issue returning result from a function

Hi I cannot return information from a function? When I try I always receive an 'undefined' message.
When I console.log the variables within the function the information appears to be correct.
The purpose of the function is to add sales data for an employee to the employee object.
This is what should happen -
{
id: 3,
firstName: 'Fred',
lastName: 'Jones',
gender: 'Non-Binary',
age: 54,
position: 'Salesperson',
sales: [{
staffId: 3,
item: 'Pre-built PC',
price: 1999.95,
date: '02-09-2022'
},
{
staffId: 3,
item: 'USB Cable',
price: 5,
date: '02-09-2022'
},
{
staffId: 3,
item: 'HDMI Cable',
price: 15.45,
date: '02-09-2022'
}
]
}
This is the function that I have -
function mapEmpAndSales() {
employeesData.map(function(employee) {
let newEmpInfo = Object.assign({}, employee);
// console.log("1");
// console.log(newEmpInfo.id);
newEmpInfo.sales = salesData.filter(function(element) {
return element.staffId == employee.id;
});
// console.log("2");
// console.log("XXXXXXXX");
// console.log(newEmpInfo);
return newEmpInfo;
// result = newEmpInfo;
});
// console.log(result);
// return result;
}
const finalresult = mapEmpAndSales();
// let newInfo = mapEmpAndSales();
console.log("XXXXXXX");
console.log(finalresult);
This line:
// return result;
is necessary to pass data back out through your function. It should not be commented out. But I don't think you want to return result, rather return employeesData variable.
return employeesData;
Your mapEmpAndSales didn't return any thing, you need return the value of employeesData.map(...).
function mapEmpAndSales() {
return employeesData.map(function(employee) {
// ....
});
}
I think is because you aren't returning in the function 'mapEmpAndSales', if you see your return is inside the 'function(employee){...}'. So, you create this function 'function(employee)' and return in that, but in the body of your main function have no return.
Try creating a const outside the map function like 'const result = []', and in your map function you add the result at it and in your main function your really return the result.
Like this:
function mapEmpAndSales() {
const result = [];
employeesData.map(function(employee) {
let newEmpInfo = Object.assign(Object.assign({}, employee));
newEmpInfo.sales = salesData.filter(function(element) {
return element.staffId == employee.id;
});
result.push(...newEmpInfo); // IF IT RETURNS A ARRAY
result.push(newEmpInfo); //IF IT RETURNS ONLY ONE VALUE
});
return result;
}
The map function returns an array, which should be captured ad returned from the mapEmpAndSales function.
The solution is already in your code, just simply uncommenting the //return result; line as the following:
function mapEmpAndSales() {
let result = employeesData.map(function(employee) {
let newEmpInfo = Object.assign({}, employee);
newEmpInfo.sales = salesData.filter(function(element) {
return element.staffId == employee.id;
});
return newEmpInfo;
});
return result;
}
const finalresult = mapEmpAndSales();
console.log(finalresult);

I am trying to make a function which will return an id from array of object

I want to write a function which will return id from array of object but when i call that function it returns me what I pass.
export function getRecipeByID(requestId) {
recipes.find(function (recipe) {
return recipe.id === requestId;
});
return requestId;
}
for example I call function
getRecipeByID(1)
and it returns 1.
I guess what you want to write is this:
export function getRecipeByID(requestId) {
return recipes.find(function (recipe) {
return recipe.id === requestId;
});
}
Notice that it doesn't return requestId but the result of recipes.find()
That's because you return requestId in your method while what you want is to return the result of recipes.find...
export function getRecipeByID(requestId) {
return recipes.find(function (recipe) {
return recipe.id === requestId;
});
}
you return requestId after using find which cause issue
const recipes = [
{
id: 2,
name: 'pasta'
},
{
id: 3,
name: 'sandwich'
},
{
id: 4,
name: 'pizza'
}
]
function getRecipeById(requestId) {
const findRecipe = recipes.find(function (recipe) {
return recipe.id === requestId;
});
return findRecipe;
}
console.log(getRecipeById(2)); // it will return{ id:2, name:"pasta" }
Try this:
export function getRecipeByID(requestId) {
const recipe = recipes.find(item => item.id === requestId);
if (recipe && recipe.id) {
return recipe.id;
} else {
return null;
}
}
Explanation: You're not assigning the result of the find operation (the element that has been found or null if there was no matching element) to any variable and are simply returning the request id.
Also: I'd suggest you'd look into arrow functions. They have been available for some years now and make your code much easier to read. :)
If you really want a function that return the same Id that you fetch, then do it:
export function getRecipeByID(requestId) {
return requestId;
}
otherwise, if want to fetch an Object of your list of object then you can simply try:
const array1 = [{}]
export function getRecipeByID(requestId) {
return array1.find(element => element.id == requestId);
}

Embed Promise within a Promise

I'm new to both node.js and Promise functionality so please forgive me if this question is really foolish.
I'm trying to make a child Promise call forEach child within a Parent call (if that makes sense).
This is my code:
return new Promise(function(resolve, reject) {
var authorMapArray = new Array
db.sequelize.query(authorQuery, {
replacements: queryParams
}).spread(function(authorSitemap) {
authorSitemap.forEach(function(obj) {
/*
return new Promise (function(resolve, reject){
var thisQuery = photoQuery + ' AND author = ' + obj.id.toString();
db.sequelize.query(thisQuery, {
queryParams
}).spread(function(authorImages) {
var authorImageArray = new Array;
authorImages.forEach(function(obj) {
var imgLink = { url: imgHost + obj.img_id + '.jpg', title : img_tags }
authorImageArray.push(imgLink);
})
});
resolve(authorImageArray);
});
*/
var authorLink = { url: 'author/' + obj.id, /*img: authorImageArray,*/ changefreq: 'weekly', priority: 0.6, lastmodrealtime: true }
siteMapArray.push(authorLink);
});
resolve(siteMapArray);
//and finally create it
createSiteMap(siteMapArray);
});
})
You'll note, the section in the middle is commented out. When I run the code like this I get the results I expect, that is the authorLink added to the sitemap. When I uncomment the code (in order to include the images associated with the author in the sitemap), not even the authorlinks are added.
How do I get the images for the author included within their record?
EDIT
This is the more complete code:
function createSiteMap(myURLs) {
var rows = 10000;
var totalMaps = Math.trunc(myURLs.length/rows)+1;
var today = new Date();
var mySitemaps = new Array;
for (var i=1; i<totalMaps+1; i++) {
var filename = "public/sitemap-" + i.toString() + ".xml";
var sitemap = sm.createSitemap({
hostname: hostname,
cacheTime: 600000, //600 sec (10 min) cache purge period
urls: myURLs.slice((i-1)*rows,i*rows)
});
fs.writeFileSync(filename, sitemap.toString());
mySitemaps.push(filename);
}
// this needs to create sitemap tags not url tags
var smi = sm.buildSitemapIndex({
urls: mySitemaps
});
fs.writeFileSync("public/sitemap.xml", smi.toString());
process.exit();
}
function uniq(a) {
var seen = {};
return a.filter(function(item) {
return seen.hasOwnProperty(item) ? false : (seen[item] = true);
});
}
function getPhotos() {
return new Promise(function(resolve, reject) {
var siteMapArray = new Array()
var tags = new Array()
siteMapArray.push ({ url: '/' , changefreq: 'weekly', priority: 0.8, lastmodrealtime: true, lastmodfile: 'views/home.hbs' },)
db.sequelize.query(photoQuery, {
replacements: queryParams
}).spread(function(makeSiteMap) {
makeSiteMap.forEach(function(obj) {
// images for sitemap
var img_tags = obj.tags.replace(/,/g , " ");
var imgLink = { url: imgHost + obj.img_id + '.jpg', title : img_tags }
var siteLink = { url: 'photo/' + obj.img_id, img: imgLink, changefreq: 'weekly', priority: 0.6, lastmodrealtime: true }
siteMapArray.push(siteLink);
obj.tags = obj.tags.split(',').map(function(e) {
return e.trim().split(' ').join('+');
});
for (var tag in obj.tags) {
tags.push(obj.tags[tag])
}
});
resolve (siteMapArray);
//tags for sitemap
var uniqueTags = uniq(tags);
for (var tag in uniqueTags) {
var siteLink = { url: '/search/' + uniqueTags[tag], changefreq: 'weekly', priority: 0.8, lastmodrealtime: true }
siteMapArray.push (siteLink);
}
//now author tags
return new Promise(function(resolve, reject) {
var authorMapArray = new Array
db.sequelize.query(authorQuery, {
replacements: queryParams
}).spread(function(authorSitemap) {
authorSitemap.forEach(function(obj) {
/*
return new Promise (function(resolve, reject){
var thisQuery = photoQuery + ' AND author = ' + obj.id.toString();
db.sequelize.query(thisQuery, {
queryParams
}).spread(function(authorImages) {
var authorImageArray = new Array;
authorImages.forEach(function(obj) {
var imgLink = { url: imgHost + obj.img_id + '.jpg', title : img_tags }
authorImageArray.push(imgLink);
})
});
resolve(authorImageArray);
});
*/
var authorLink = { url: 'author/' + obj.id, /*img: authorImageArray,*/ changefreq: 'weekly', priority: 0.6, lastmodrealtime: true }
siteMapArray.push(authorLink);
});
resolve(siteMapArray);
//and finally create it
createSiteMap(siteMapArray);
});
})
});
});
};
getPhotos();
Okay, let's assume that you want something like this:
function getSiteMapArray() {
// return a promise that resolves to the siteMapArray
}
First step would be to rewrite it without using new Promise() - you shouldn't be needing this one very often, since most of work with promises is just chaining .then() calls which is much more readable.
Note that .spread() is just a .then() with sugar on top. The sugar is not standard Promise syntax, but rather an addon from bluebird that sequelize recommends to use. These are equivalent for a promise that resolves with array with 2 values:
something.then(resultArray => ...);
something.spread((resultItem1, resultItem2) => ...);
(I'm going to use arrow functions, is that OK?)
So the first step is to get rid of new Promise() as promised, before we start incorporating the code from your comments:
function getSiteMapArray() {
var authorMapArray = new Array();
return db.sequelize
.query(authorQuery, {
replacements: queryParams
})
.spread(authorSitemap => {
authorSitemap.forEach(function(obj) {
var authorLink = {
url: "author/" + obj.id,
/*img: authorImageArray,*/
changefreq: "weekly",
priority: 0.6,
lastmodrealtime: true
};
siteMapArray.push(authorLink);
});
return siteMapArray;
});
}
Simple enough?
We use .query() to get a promise of results,
then we use .then() or .spread() passing a callback that processes the results,
spread() returns a new promise that resolves when we're done with everything, and this promise is the result of getSiteMapArray(). It's going to resolve with the value from return siteMapArray.
We could simplify one step further with map() instead of forEach which is recommended whenever you want to transform each element in an array:
function getSiteMapArray() {
return db.sequelize
.query(authorQuery, {
replacements: queryParams
})
.spread(authorSitemap => {
return authorSitemap.map(obj => ({
url: "author/" + obj.id,
/*img: authorImageArray,*/
changefreq: "weekly",
priority: 0.6,
lastmodrealtime: true
}));
});
}
So that was the easy part, now how do we incorporate the authorImage query here?
Let me extract a helper first:
function getSiteMapArray() {
return db.sequelize
.query(authorQuery, {
replacements: queryParams
})
.spread(authorSitemap => {
return authorSitemap.map(getAuthorDescription);
});
}
function getAuthorDescription(obj) {
return {
url: "author/" + obj.id,
/*img: authorImageArray,*/
changefreq: "weekly",
priority: 0.6,
lastmodrealtime: true
};
}
Now getAuthorDescription is synchronous, but we want it to do a query on its own, so let's rewrite it to async, so that it returns a promise too!
function getAuthorDescription(obj) {
var thisQuery = photoQuery + " AND author = " + obj.id.toString();
return db.sequelize
.query(thisQuery, {
queryParams
})
.spread(function(authorImages) {
var authorImageArray = new Array();
authorImages.forEach(function(obj) {
var imgLink = { url: imgHost + obj.img_id + ".jpg", title: img_tags };
authorImageArray.push(imgLink);
});
return {
url: "author/" + obj.id,
img: authorImageArray,
changefreq: "weekly",
priority: 0.6,
lastmodrealtime: true
};
});
}
Another great case to use .map() but I'll leave that one for you.
Back to the original code:
function getSiteMapArray() {
return db.sequelize
.query(authorQuery, {
replacements: queryParams
})
.spread(authorSitemap => {
return authorSitemap.map(getAuthorDescription); // !!!
});
}
Wow, now we're in trouble - getAuthorDescription returns a promise, so we're resolving getSiteMapArray with a list of promises, instead of list of values!
We need a way to wait for each of the promises returned from getAuthorDescription to finish, and obtain an array of collected results of all these promises. This way is called Promise.all:
So the code becomes:
function getSiteMapArray() {
return db.sequelize
.query(authorQuery, {
replacements: queryParams
})
.spread(authorSitemap => {
return Promise.all(authorSitemap.map(getAuthorDescription));
});
}
Let me know if this helps!
There are couple of issues in your implementation. I will suggest not to use [].foreach for child promise. make separate method for child promise and called it for each authorSitemap using promise.all.
Below is sample implementation with update.
return new Promise(function(resolve, reject) {
var authorMapArray = new Array
db.sequelize.query(authorQuery, {
replacements: queryParams
}).spread(function(authorSitemap) {
return Promise.all(authorSitemap.map(GetAuthor))
.then(function(authorImageArray){
var authorLink = { url: 'author/' + obj.id, img: authorImageArray, changefreq: 'weekly', priority: 0.6, lastmodrealtime: true }
siteMapArray.push(authorLink);
createSiteMap(siteMapArray);
resolve(siteMapArray);
})
.catch(function(error){
reject(error);
})
});
})
function GetAuthor(obj) {
return new Promise(function(reject,resolve){
var thisQuery = photoQuery + ' AND author = ' + obj.id.toString();
db.sequelize.query(thisQuery, { queryParams})
.spread(function(authorImages) {
var authorImageArray = new Array;
authorImages.forEach(function(obj) {
var imgLink = { url: imgHost + obj.img_id + '.jpg', title : img_tags }
authorImageArray.push(imgLink);
})
resolve(authorImageArray);
});
})
}

Mongoose save with promises and populate

I have the following code (Mongoose has been promisified with Bluebird)
function createNewCourse(courseInfo, teacherName) {
var newCourse = new courseModel({
cn: courseInfo.courseName,
cid: courseInfo.courseId
});
return newCourse.saveAsync()
.then(function (savedCourse) {
var newTeacher = new newTeacherModel({
na: teacherName,
_co: savedCourse._id // This would be an array
});
return newTeacher.saveAsync().then(function() {
return newCourse;
});
});
}
This is a simplification of my problem, but it illustrates it well. I want my createNewCourse function to return a promise that, once resolved, will return the newly saved course, not the teacher. The above code works, but it's not elegant and does not use promises well to avoid callback hell.
Another option I considered is returning the course and then doing a populate, but that would mean re-querying the database.
Any ideas how to simplify this?
Edit: I thought it might be useful to post the save code but using native callbacks (omitting error-handling)
function createNewCourse(courseInfo, teacherName, callback) {
var newCourse = new courseModel({
cn: courseInfo.courseName,
cid: courseInfo.courseId
});
newCourse.save(function(err, savedCourse) {
var newTeacher = new newTeacherModel({
na: teacherName,
_co: savedCourse._id // This would be an array
});
newTeacher.save(function(err, savedTeacher) {
callback(null, newCourse);
});
});
}
Use .return():
function createNewCourse(courseInfo, teacherName) {
var newCourse = new courseModel({
cn: courseInfo.courseName,
cid: courseInfo.courseId
});
return newCourse.saveAsync().then(function (savedCourse) {
var newTeacher = new newTeacherModel({
na: teacherName,
_co: savedCourse._id // This would be an array
});
return newTeacher.saveAsync();
}).return(newCourse);
}
Remember how chaining works?
.then(function() {
return somethingAsync().then(function(val) {
...
})
})
Is equivalent to (disregarding any closure variables):
.then(function() {
return somethingAsync()
})
.then(function(val) {
...
})
return(x) is simply equivalent to .then(function(){return x;})

AngularJS $q.all & multiple $q.defer

Even though I have managed to make my code work, there is something I don't understand. The following piece of code functions correctly:
socket.on('method', function() {
var payload = {
countrycode: '',
device: ''
};
var d1 = $q.defer();
var d2 = $q.defer();
$q.all([
geolocation.getLocation().then(function(position) {
geolocation.getCountryCode(position).then(function(countryCode){
payload.countrycode = countryCode;
d1.resolve(countryCode);
});
return d1.promise;
}),
useragent.getUserAgent().then(function(ua) {
useragent.getIcon(ua).then(function(device) {
payload.device = device;
d2.resolve(device);
});
return d2.promise
})
]).then(function(data){
console.log(data); //displays ['value1', 'value2']
})
});
Is there a better way of achieving this? Before I had only one deferred variable, i.e. varvar deferred = $q.defer(); but that way the .then() function returned an object with double the results.
So the few question I have are:
Do I need multiple $q.defer vars?
Is the above the best way to wait for two async calls to finish and populate the payload object?
socket.on('method', function() {
var payload = {
countrycode: '',
device: ''
};
geolocation.getLocation()
.then(function(position) {
return geolocation.getCountryCode(position);
})
.then(function(countryCode) {
payload.countrycode = countryCode;
return useragent.getUserAgent();
})
.then(function(ua) {
return useragent.getIcon(ua);
})
.then(function(device) {
payload.device = device;
console.log(data); //displays ['value1', 'value2']
});
});
read the promise chaining part
You could always separate your code into smaller semantic blocks like so:
getCountryCode = function() {
var d = $q.defer();
geolocation.getLocation()
.then(function(position) {
return geolocation.getCountryCode(position)
})
.then(function(countryCode) {
d.resolve(countryCode);
})
.fail(function(err) {
d.reject(err);
})
return d.promise;
};
getDevice = function() {
var d = $q.defer();
useragent.getUserAgent()
.then(function(ua) {
return useragent.getIcon(ua)
})
.then(function(device) {
d.resolve(device);
})
.fail(function(err) {
d.reject(err);
});
return d.promise;
}
That will shorten your actual parallel call ($q.all) quite a bit:
socket.on('method', function() {
$q.all([getCountryCode(), getDevice()])
.spread(function(countryCode, device) {
var payload = {
countryCode: countryCode,
device: device
};
// ... do something with that payload ...
});
});
To synchronize multiple asynchronous functions and avoid Javascript callback hell:
http://fdietz.github.io/recipes-with-angular-js/consuming-external-services/deferred-and-promise.html

Categories