I try this code:
function addNewCars(req, res) {
let CarsList = req.body;
carListParsing(carList)
.then(function () {
console.log('OK');
res.status(200).send('OK');
}).catch(function (err) {
res.status(200).send(err);
});
}
function carListParsing (data) {
return new Promise(function (resolve, reject) {
let newCar = {};
newCar.name = data.car_name;
validateCar(newCar).then(function (data) {
console.log('validate result1: ', data); //this line doesn't show
//if I get validation result, I can use next function createCat()
resolve(data);
}).catch(function (err) {
reject(err);
});
});
}
function validateCar(data) {
db.cars.findAll({where: {name: data.name}}).then(function (org) {
if (org.length < 1) {
console.log('validate1: OK'); //work
return data;
} else {
console.log('validate2: already exist'); //work
return new Error('The ' + data.name + ' car is already exist.');
}
}).catch(function (err) {
return err;
});
}
I neet to validate data => Car name, if car not exist then create new car and perform next logic, example park car. If car found, then perform function park car.
Avoid the Promise constructor antipattern in carListParsing, and return your result promise from validateCar!
function addNewCars(req, res) {
// CarsList is a typo
carListParsing(req.body)
.then(function () {
console.log('OK');
res.status(200).send('OK');
}, function (err) { // more appropriate than catch
res.status(200).send(err);
});
}
function carListParsing (data) {
let newCar = {
name: data.car_name
};
// don't call `new Promise`
return validateCar(newCar).then(function (data) {
console.log('validate result1: ', data); //this line doesn't show
// if I get validation result, I can use next function createCat()
return data; // don't resolve
});
}
function validateCar(data) {
return db.cars.findAll({where: {name: data.name}}).then(function (org) {
// ^^^^^^
if (org.length < 1) {
console.log('validate1: OK'); //work
return data;
} else {
console.log('validate2: already exist'); //work
throw new Error('The ' + data.name + ' car is already exist.');
// ^^^^^ probably what you actually wanted
}
}) // don't ignore errors
}
Related
I am using async parallel to get data from db in parallel.
When every task is returning the data I am storing it in local object.
From index.js I am calling cacheService.js .
In cacheService.js I am loading data from mysql database and mongo database in to cache object.
Whenever I am doing npm run local run. I am getting following error.
UNHANDLEDREJECTION Error: Callback was already called.
This error is coming from loadMongoData method of cacheService.js.
I have followed other answers on stackoverflow like adding else part
Here is code for cacheService.js.
'use strict';
var cache = [];
class cacheService {
async init() {
await this.loadMongoData();
}
loadMongoData(env, callback1) {
const _this = this;
console.log('Inside loadMongoData')
async.parallel(
{
task1: function (callback) {
CriteriaDef.find({})
.lean()
.exec(function (err, criteriaDefs) {
if (err) {
console.log('Inside err 1')
logger.error('Error fetching CriteriaDef: ', util.inspect(err));
callback(err, null);
} else if (criteriaDefs) {
console.log('Inside criteriaDefs')
if (criteriaDefs.length && criteriaDefs.length > 0) {
console.log('Inside criteriaDefs 1')
global.CRITERIA_DEFS = criteriaDefs;
cache['criteria_defs'] = criteriaDefs;
}
callback(null, null);
}
});
},
task2: function (callback) {
groupDef
.find({})
.lean()
.exec(function (err, groupDefs) {
if (err) {
console.log('Inside err2')
logger.error('Error fetching groupDefs: ', util.inspect(err));
callback(null, err);
} else if (groupDefs) {
console.log('Inside ')
global.groupDefsWithRoles = groupDefs;
let _groupDefs = [];
_.each(groupDefs, function (groupDef) {
var data = {
value: groupDef._id,
label: `${groupDef._id}: ${groupDef.description}`
};
_groupDefs.push(data);
});
global.groupDefs = _groupDefs;
cache['groupDefs'] = _groupDefs;
logger.info('Loaded groupDefs: ', global.groupDefs.length);
callback(null, null);
}
});
},
task3: function (callback) {
jiraProjects.find({$or: [{archived: {$ne: true}}, {archived: {$exists: false}}]}).exec(function (err, jiraProjects) {
if (err) {
console.log('Inside error 3')
logger.error('Error fetching jiraProjects: ', err);
callback(null, err);
} else if (jiraProjects) {
console.log('Inside jira project')
let _jiraProjects = [];
_.each(jiraProjects, function (jiraProject) {
var data = {
value: jiraProject.key,
label: jiraProject.key,
issueType: jiraProject.issueType ? jiraProject.issueType : 'Bug'
};
_jiraProjects.push(data);
});
global.jiraProjectsList = _jiraProjects;
cache['jiraProjects'] = _jiraProjects;
logger.info('Loaded jira projects: ', global.jiraProjectsList.length);
callback(null, null);
}
});
},
task4: function (callback) {
console.log('Inside task4')
callback(null, null);
},
task5: function (callback) {
inputElements
.find({})
.lean()
.exec(function (err, inputElements) {
if (err) {
console.log('Inside error5')
logger.error('Error fetching inputElements: ', util.inspect(err));
callback(null, err);
} else if (inputElements) {
console.log('Inside inputelements')
global.INPUT_ELEMENTS_DEF = inputElements;
cache['INPUT_ELEMENTS_DEF'] = inputElements;
callback(null, null);
}
});
},
task6: function (callback) {
console.log('Inside task6')
sisp.loadProducts('', callback);
}
},
function (err, results) {
if (err) {
console.log('Inside final error')
logger.error("Something went wrong can't start the app: ", util.inspect(err));
callback1(null, err);
} else {
console.log('Inside final else')
logger.info('loaded all globals properly :)');
callback1(null, null);
}
}
)
}
}
export default new cacheService();
I think your problem cuz you use callback inside of promise.
Please change your code like this:
class cacheService {
async init() {
await new Promise((resolve, reject) => {
this.loadMongoData(env, (ignoreArg, error) => {
if (error) {
return reject(error);
}
resolve();
});
});
}
...
}
Tip: in the each task add statement else for call callback, because maybe your statement not handled and your code can't execute prefect
task1: function (callback) {
CriteriaDef.find({})
.lean()
.exec(function (err, criteriaDefs) {
if (err) {
console.log('Inside err 1')
logger.error('Error fetching CriteriaDef: ', util.inspect(err));
callback(err, null);
} else if (criteriaDefs) {
console.log('Inside criteriaDefs')
if (criteriaDefs.length && criteriaDefs.length > 0) {
console.log('Inside criteriaDefs 1')
global.CRITERIA_DEFS = criteriaDefs;
cache['criteria_defs'] = criteriaDefs;
}
callback(null, null);
} else {
callback(null, null);
}
});
},
I want to integrate Stripe into my application. I have collected all necessary Data in the req.body.
Now an undefined error is being thrown after creating the customer Id and while trying to pass it to addCustomerToCard. After that, createToken is being successfully logged.
So two questions:
1.Why is the order of functions not being invoked as I would expect?
2.Why does the customer not get passed in addCustomerToCard?
router.post("/checkout", async function (req, res, next) {
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
let createCustomer = function () {
var param ={};
param.email = req.body.email;
param.name= req.body.name;
param.description ="";
return stripe.customers.create(param, function (err, customer) {
if (err) {
console.log("err:" + err);
}
if (customer) {
console.log("success: " + JSON.stringify(customer, null, 2));
} else {
console.log("something went wrong");
}
});
};
let createToken = function () {
let param ={};
param.card = {
number: req.body.card,
exp_month: req.body.exp_month,
exp_year: req.body.exp_year,
cvc: req.body.security
}
return stripe.tokens.create(param, function (err, token) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (token) {
console.log("success: " + JSON.stringify(token, null, 2));
console.log(req.body);
} else {
console.log("something went wrong");
}
});
};
let addCardToCustomer = function () {
console.log(createdCustomer);
return stripe.customers.createSource(customer.id, {source: token.id}, function (err, card) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (card) {
console.log("success: " + JSON.stringify(card, null, 2));
} else {
console.log("something went wrong");
}
});
};
let chargeCustomerThroughCustomerID = function () {
let param = {
amount: cart.totalPrice,
currency: 'eur',
description: 'First payment',
customer: customer.id
}
stripe.charges.create(param, function (err, charge) {
if (err) {
console.log("err: " + err);
}
if (charge) {
console.log("success: " + JSON.stringify(charge, null, 2));
} else {
console.log("Something wrong")
}
})
}
try {
const createdCustomer = await createCustomer(); // promise 1
const createdToken = await createToken();
const addedCardToCustomer = await addCardToCustomer(createdCustomer,createdToken ); //
// const chargeCustomerThroughCustomerID = await chargeCustomerThroughCustomerID(); // promise 4
res.send("success");
} catch (e) {
console.log(`error ${e}`)
};
});
//LOG OUTPUT
//success
//error ReferenceError: createdCustomer is not defined
//success
You should break this down into smaller pieces to verify the behaviour you're expecting, for starters. There's quite a lot going on here.
One problem is that you are trying to await functions which are not async -- you should have each function marked:
let createCustomer = async function () {...}
This is likely the reason the sequence is not what you expect.
You're hitting an error in addCardToCustomer because createCustomer is undefined in the scope of that function. You need to have a parameter:
let addCardToCustomer = async function (createdCustomer) { ... }
I have this service
service.getCurrentUser = function () {
var def = $q.defer();
if (service.user == null)
{
$http.get("./api/GetCurrentUser/")
.success(function(data) {
service.user=data;
def.resolve(data);
})
.error(function() {
def.reject("Failed to get user");
});
}
else
def.resolve(service.user);
return def.promise;
}
in my controller I want to call this and wait for return then if the user is in a certain group run other code
How do I write it so it uses the promise returned by the service
The promise implementation can be like:
service.getCurrentUser = function () {
return new Promise((resolve,reject)=>{
if (service.user == null) {
$http.get("./api/GetCurrentUser/")
.success(function (data) {
service.user = data;
resolve(data);
})
.error(function () {
reject("Failed to get user");
});
}else{
resolve(service.user);
}
});
}
You can call it as:
service.getCurrentUser()
.then(user => {
console.log('user', user);
})
.catch(error => {
console.log('error', error);
});
I would like to call a function which takes data for every student for a specific time interval and repeat the same process until it reaches some condition.
The current code it seems to make parallel calls to the function iterateThruAllStudents();
My code looks like this:
var startDate = new Date("March 16, 2016 00:00:00"); //Start from February
var fromTimestamp = null;
var toTimestamp = null;
var today = new Date();
var todayTimestamp = new Date(today).getTime() / 1000;
async.whilst(
function () {
return fromTimestamp < todayTimestamp;
},
function (callback) {
console.log(startDate);
fromTimestamp = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 5);
toTimestamp = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(fromTimestamp, toTimestamp);
callback(null, startDate);
},
function (err, n) {
console.log('finished for ' + n);
}
);
function iterateThruAllStudents(from, to) {
Student.find({status: 'student'})
.populate('user')
.exec(function (err, students) {
if (err) {
throw err;
}
var counter = 0;
async.eachSeries(students, function iteratee(student, callback) {
if (student.worksnap.user != null) {
var worksnapOptions = {
hostname: 'api.worksnaps.com',
path: '/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
headers: {
'Authorization': 'Basic ' + auth_hash
},
method: 'GET'
};
getTimeEntries(worksnapOptions)
.then(function (response) { //callback invoked on deferred.resolve
return convertXMLToJson(response);
}).then(function (timeEntries) {
console.log('convert xml to json');
var isEmpty = _.isEmpty(timeEntries); // true
if (isEmpty) {
callback(null);
}
return saveTimeEntry(timeEntries);
}).then(function (response) {
counter++;
console.log('all timeEntries for one student finished....Student: ' + student.worksnap.user.user_id + ' Student Counter: ' + counter);
callback(null);
});
} else {
callback(null);
}
});
});
}
function convertXMLToJson(response) {
var deferred = Q.defer();
parser.parseString(response, function (err, results) {
if (err) {
deferred.reject(err);
}
var json_string = JSON.stringify(results.time_entries);
var timeEntries = JSON.parse(json_string);
deferred.resolve(timeEntries);
});
return deferred.promise;
}
function saveTimeEntry(timeEntries) {
var deferred = Q.defer();
_.forEach(timeEntries.time_entry, function (item) {
Student.findOne({
'worksnap.user.user_id': item.user_id[0]
})
.populate('user')
.exec(function (err, student) {
if (err) {
deferred.reject(err);
}
student.worksnap.timeEntries.push(item);
student.save(function (err) {
if (err) {
deferred.reject(err);
} else {
//console.log(item);
}
});
});
});
deferred.resolve('finished saving timeEntries for one student...');
return deferred.promise;
}
function getTimeEntries(requestOptions) {
//create a deferred object from Q
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var deferred = Q.defer();
var req = http.request(requestOptions, function (response) {
//set the response encoding to parse json string
response.setEncoding('utf8');
var responseData = '';
//append data to responseData variable on the 'data' event emission
response.on('data', function (data) {
responseData += data;
});
//listen to the 'end' event
response.on('end', function () {
//resolve the deferred object with the response
console.log('http call finished');
deferred.resolve(responseData);
});
});
//listen to the 'error' event
req.on('error', function (err) {
//if an error occurs reject the deferred
console.log('inside On error.');
console.log(err);
deferred.reject(err);
});
req.end();
//we are returning a promise object
//if we returned the deferred object
//deferred object reject and resolve could potentially be modified
//violating the expected behavior of this function
return deferred.promise;
}
Anyone has an idea how to achieve such thing that I can grab data for all students synchronously for each time interval?
Take a look at the docs for async.eachSeries() (alias of #each()). You'll want to supply a third argument, and call the callback originating from the argument in the second function of async.whilst().
I think the following modifications will do what you need. Take a look for the callback I named done, specifically:
var startDate = new Date("March 16, 2016 00:00:00"); //Start from February
var fromTimestamp = null;
var toTimestamp = null;
var today = new Date();
var todayTimestamp = new Date(today).getTime() / 1000;
async.whilst(
function () {
return fromTimestamp < todayTimestamp;
},
function (callback) {
console.log(startDate);
fromTimestamp = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 5);
toTimestamp = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(fromTimestamp, toTimestamp, callback);
},
function (err, n) {
console.log('finished for ' + n);
}
);
function iterateThruAllStudents(from, to, done) {
Student.find({status: 'student'})
.populate('user')
.exec(function (err, students) {
if (err) {
throw err;
}
var counter = 0;
async.eachSeries(students, function iteratee(student, callback) {
if (student.worksnap.user != null) {
var worksnapOptions = {
hostname: 'api.worksnaps.com',
path: '/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
headers: {
'Authorization': 'Basic ' + auth_hash
},
method: 'GET'
};
getTimeEntries(worksnapOptions)
.then(function (response) { //callback invoked on deferred.resolve
return convertXMLToJson(response);
}).then(function (timeEntries) {
console.log('convert xml to json');
var isEmpty = _.isEmpty(timeEntries); // true
if (isEmpty) {
callback(null);
}
return saveTimeEntry(timeEntries);
}).then(function (response) {
counter++;
console.log('all timeEntries for one student finished....Student: ' + student.worksnap.user.user_id + ' Student Counter: ' + counter);
callback(null);
});
} else {
callback(null);
}
}, function eachSeriesFinished(err) {
if (err)
return done(err);
return done(null, to);
});
});
}
function convertXMLToJson(response) {
var deferred = Q.defer();
parser.parseString(response, function (err, results) {
if (err) {
deferred.reject(err);
}
var json_string = JSON.stringify(results.time_entries);
var timeEntries = JSON.parse(json_string);
deferred.resolve(timeEntries);
});
return deferred.promise;
}
function saveTimeEntry(timeEntries) {
var deferred = Q.defer();
_.forEach(timeEntries.time_entry, function (item) {
Student.findOne({
'worksnap.user.user_id': item.user_id[0]
})
.populate('user')
.exec(function (err, student) {
if (err) {
deferred.reject(err);
}
student.worksnap.timeEntries.push(item);
student.save(function (err) {
if (err) {
deferred.reject(err);
} else {
//console.log(item);
}
});
});
});
deferred.resolve('finished saving timeEntries for one student...');
return deferred.promise;
}
function getTimeEntries(requestOptions) {
//create a deferred object from Q
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var deferred = Q.defer();
var req = http.request(requestOptions, function (response) {
//set the response encoding to parse json string
response.setEncoding('utf8');
var responseData = '';
//append data to responseData variable on the 'data' event emission
response.on('data', function (data) {
responseData += data;
});
//listen to the 'end' event
response.on('end', function () {
//resolve the deferred object with the response
console.log('http call finished');
deferred.resolve(responseData);
});
});
//listen to the 'error' event
req.on('error', function (err) {
//if an error occurs reject the deferred
console.log('inside On error.');
console.log(err);
deferred.reject(err);
});
req.end();
//we are returning a promise object
//if we returned the deferred object
//deferred object reject and resolve could potentially be modified
//violating the expected behavior of this function
return deferred.promise;
}
Side note, if you were open to it, using something like co or async/await would simplify this code a lot, in my opinion.
I use the following code to generate a unique token for a user. Data for users is stored on MongoDB so I use promise to handle asynchronous talking to the db. In WebStorm I receive this warning : Mutable variable is accessible from closure with promise and loop. and I know there have been posts on SO about this thing, but I my case is more complicated. I know I may not even need to worry about it as I only use the last value of token but what I want to solve this issue in a correct way ?
var generateToken = function(userId) {
User.findOne({userId: userId}, function(err, user) {
if (user !== null) {
var loop = true;
while (loop) {
var token = Common.randomGenerator(20);
User.find({tokens: token}, function(err, result) {
if (err) {
loop = false;
return Promise.reject('Error querying the database');
} else {
if (result.length === 0) {
if (user.tokens === undefined){
user.tokens.push(token);
}
loop = false;
return Promise.resolve(token);
}
}
});
}
} else {
return Promise.reject('UserNotFound');
}
});
};
I came up with the following solution , is it correct ?
var generateToken = function(userId) {
User.findOne({userId: userId}, function(err, user) {
if (user !== null) {
var loop = true;
while (loop) {
var token = Common.randomGenerator(20);
(function(e){
User.find({tokens: e}, function(err, result) {
if (err) {
return Promise.reject('Error querying the database');
} else {
if (result.length === 0) {
if (user.tokens === undefined){
user.tokens = [];
}
user.tokens.push(e)
return Promise.resolve(e);
}
}
});
})(token);
}
} else {
return Promise.reject('UserNotFound');
}
});
};
NOTE As #Alex Nikulin suggested , I flipped loop to false before sending back the result of the promise. But still it's an infinite loop as it doesn't go into the User.find({tokens: e})....
Your problem is that, return statement is within function, not within loop.Your loop is infinite. I has decomposited your code.Or simply make loop false, when you resolve/reject promise. Also my code will wait each answer from User, and error will gone. And your variant with wrap function is correct (function(e){})(token).
var generateToken = function(userId) {
return new Promise(function(resolve, reject) {
User.findOne({userId: userId}, function(err, user) {
if (user !== null) {
userTokenIterator(user,resolve, reject);
} else {
reject('UserNotFound');
}
});
});
};
var addTokenToUser = function(token,user){
return new Promise(function(resolve, reject) {
User.find({tokens: token}, function(err, result) {
if (err) {
reject('Error querying the database');
} else {
var result = result.length === 0;
if (result) {
if(!user.tokens) {
user.tokens = []
}
user.tokens.push(token);
}
resolve(result);
}
});
});
};
var userTokenIterator = function (user, resolve, reject){
var token = Common.randomGenerator(20);
addTokenToUser(token, user).then(function(result){
if(result) {
resolve(token);
}else{
userTokenIterator(user,resolve, reject)
}
},function(error){
reject(error);
});
};