I'm working on a app and hit a corner stone with spaghetti Promise code which baffles me. Must mention it's my first try at Promise (in a attempt to ditch callback hell).
I'm using node.js and need a module to get data from Goodreads API to other part of the application so I can use it. I made a object that I export in the module which has a function return a Promise chain.
The issue lies when I call this module in the main part of the app. If the Goodreads module API created by me ends in the .reject() from the Promise, both .then() and .catch() are called. More inline comments in the code.
This is my code:
goodreads_module.js:
let goodreads = {
getItem: function(path) {
if (typeof path == 'object') {
return path._;
} else {
return path;
}
},
// Get the book id needed for further search of book language on different api end-point
getBookId: function(word) {
let self = this;
logger.log(logger.info, 'Getting book process started!');
// Query for GoodRead search
const query_book = {
q: word,
page: '',
type: 'title'
};
logger.log(logger.info, 'Seaching by word: ' + query_book.q);
return new Promise((resolve, reject) => {
// Searching for book using
// #param: query_book
if (typeof query_book !== 'undefined') {
// directly resolve with the promise
return resolve(grclient.searchBooks(query_book));
} else {
let reason = 'No word to search for';
return reject(reason);
}
})
.then((result) => {
let search = result.search,
rating,
book_id,
random_nr,
ratings_count,
count = 0;
if(parseInt(search['total-results']) == 0){
return false;
}
if (parseInt(search['total-results']) !== 0 && !Array.isArray(search.results.work)) {
logger.log(logger.info, 'Book data is:\n' + JSON.stringify(search.results.work));
rating = self.getItem(search.results.work.average_rating)
ratings_count = self.getItem(search.results.work.ratings_count);
book_id = search.results.work.best_book.id._;
}
if (parseInt(search['total-results']) > 1 && Array.isArray(search.results.work)) {
random_nr = Math.floor(Math.random() * search.results.work.length);
logger.log(logger.info, 'Book data is:\n' + JSON.stringify(search.results.work[random_nr]));
rating = self.getItem(search.results.work[random_nr].average_rating)
ratings_count = self.getItem(search.results.work[random_nr].ratings_count);
// If the book grabed has the rating lower than 3.8 grab another book
do {
random_nr = Math.floor(Math.random() * search.results.work.length);
rating = self.getItem(search.results.work[random_nr].average_rating)
ratings_count = self.getItem(search.results.work[random_nr].ratings_count);
logger.log(logger.warn, 'New book data is:\n' + JSON.stringify(search.results.work[random_nr]));
count++;
if (count == 10) {
break;
}
} while (rating <= 3.8 && ratings_count <= 5 || rating <= 3.8 && ratings_count >= 5 || rating >= 3.8 && ratings_count <= 5)
if (count == 10) {
return false;
}
console.log(count);
logger.log(logger.info, 'Book rating / rating rount ' + JSON.stringify(rating) + "/" +JSON.stringify(ratings_count));
// Grab the book id when all rules are met
book_id = search.results.work[random_nr].best_book.id._;
}
if (rating <= 3.8 && ratings_count <= 5 || rating <= 3.8 && ratings_count >= 5 || rating >= 3.8 && ratings_count <= 5) {
return false;
}
return parseInt(book_id);
})
},
// Finally get the book using the book id and return book data in a object containing author, title and url.
getBook: function(word) {
let self = this;
return new Promise((resolve, reject) => {
self.getBookId(word).then((result) => {
if (typeof result == 'boolean') {
let reason = 'Book id invalid';
return reject(reason);
}
return resolve(result);
})
})
.then((result) => {
logger.log(logger.info, 'Check language for book id: ' + result);
return new Promise((resolve, reject) => {
grclient.showBook(result).then((response) => {
let data = response.book;
let lang = data.language_code;
logger.log(logger.info, 'Book language is ' + JSON.stringify(lang));
if (lang == 'eng' || lang == 'en-US' || lang == 'en-GB' || lang == 'English' || lang == 'english' || lang == 'en-US') {
let book = {
title: data.title,
author: data.authors.author.name ? data.authors.author.name : data.authors.author[0].name,
url: data.url
}
return resolve(book);
} else {
let reason = 'Language is not english';
return reject(reason);
}
})
})
})
},}
main.js:
goodreads.getBook(goodreads.word()).then((data)=>{
logger.log(logger.info, "Got the book! Continue with tweeting process");
// use data here
})
What am I doing wrong as the .catch() method should be the only one called in main.js without short call on .then()? How should I chain this promises?
There can be a problem regarding .then and .catch. According to mdn, the promise.then takes two callbacks, one for success and other for rejection. If you'll specify a catch after then then it might well be the case that your code is breaking in then's first callback. e.g.
someAPICall()
.then(() => {//if code breaks here it'll go in catch too})
.catch(() => {//can come here})
But if you want to write code for promise rejection. You must provide then a second callback as :
someAPICall()
.then(() => {
//success
}, () => {
//rejection
});
I'm sorry I didn't read your whole code and it might as well be the case that this isn't the primary reason. If the answer doesn't help please comment. Hope that helps.
You're kind of misusing promises, unless you're doing something asynchronous, you don't need to create a new promise every time.
Just return a value if you want to a new fulfilled promise or throw if you want a new rejected promise.
new Promise((res, reject) => {
res(true);
}).then(val => {
return false;
}).then(val => console.log(val)); // false
new Promise((res, reject) => {
res(true);
}).then(val => {
throw "foo";
}).catch(err => console.log(err)); // "foo"
Another important point about promises is that if you return a promise, the new promise generated will be resolved / rejected accordingly to the returned promise, so the beginning of your code could be simplify to
return new Promise((resolve, reject) => {
if (typeof query_book !=='undefined') {
// directly resolve with the promise
return resolve(grclient.searchBooks(query_book));
} else {
let reason = 'No word to search for';
return reject(reason);
}
});
Ended up re-writing the code as above and the problem was gone.
Spaghetti monster code is a bad practice and should be avoided.
Related
I am trying to apply a promise to getting cookies from the browser
browserCookies = {
art_rfp : '',
art_token : ''
};
var promise = new Promise((resolve, reject) => {
chrome.cookies.getAll({"url":"https://url.com"}, function (cookies) {
for(var i=0; i<cookies.length; i++){
var name = cookies[i].name
// console.log(name)
if (name == 'sso_rfp') {
console.log(name) // line 13
browserCookies.art_rfp = cookies[i].value
resolve('cookies found')
}
else if (name == 'sso_token') {
console.log(name) // line 18
browserCookies.art_token = cookies[i].value
}
else {
reject('no cookies found')
}
}
});
})
promise.then((message) => {
console.log(message)
}).catch((message) =>{
console.log(message)
})
However it is just failing.
background.js:13 sso_rfp
background.js:18 amzn_sso_token
background.js:32 no cookies found
why isn't it resolving?
Promises can only be rejected / resolved once.
So what's likely happening inside your loop, the first cookie's name is neither sso_rfp or sso_token as such it will call reject('no cookies found'), so even if more are found later, they cannot get resolved because the reject has already been called.
So what you want to do is keep a track using a simple boolean wherever a cookie was found or not found, and then resolve / reject at the end.
eg..
var promise = new Promise((resolve, reject) => {
chrome.cookies.getAll({"url":"https://url.com"}, function (cookies) {
var found = false;
for(var i=0; i<cookies.length; i++){
var name = cookies[i].name
// console.log(name)
if (name == 'sso_rfp') {
console.log(name) // line 13
browserCookies.art_rfp = cookies[i].value
found = true;
}
else if (name == 'sso_token') {
console.log(name) // line 18
browserCookies.art_token = cookies[i].value;
found = true;
}
}
if (found) resolve("Cookies Found");
else reject("no cookies found");
});
})
Also just a coding standard, I would personally avoid using a global browserCookies, and instead resolve with these values instead.
I'm learning about Promise's and have a little doubt assuming that I want to get resolved status out of Promises
and not want reject! Can I just call back the promise function inside
catch to make sure that I get only approved value! Is that possible or
will it throw an error or goes to loop iteration
let promisetocleantheroom = new Promise(function cleanroom(resolve, reject) {
//code to clean the room
//then as a result the clean variable will have true or flase
if (clean == "true") {
resolve("cleaned");
} else {
reject("not cleaned");
}
});
promisetocleantheroom.then(function cleanroom(fromResolve) {
// wait for the function to finish only then it would run the function then
console.log("the room is " + fromResolve);
}).catch(function cleanroom(fromReject) {
//calling back the promise again
cleanroom();
});
If you don't mind having higher order functions and recursivity, here is my proposed solution.
First you need to wrap your promise in a function to recreate it when it fails. Then you can pass it to retryPromiseMaker with a partial error handler to create another function that will act as retrier. And this function will return a Promise that will fulfill only if one of the inner promises fulfills.
Sounds complicated but I promise you it is not!
const retryPromiseMaker = (fn, errorfn = null) => {
const retryPromise = (retries = 3, err = null) => {
if (err) {
errorfn(err);
}
if (retries === 0) {
return Promise.reject(err);
}
return fn()
.catch(err => retryPromise(retries - 1, err));
};
return retryPromise;
}
const cleanTheRoom = (resolve, reject) => {
// simulate cleaning as a probability of 33%
const clean = Math.random() < 0.33;
setTimeout(() => {
if (clean) {
resolve("cleaned");
} else {
reject("not cleaned");
}
}, Math.random() * 700 + 200);
};
const promiseToCleanTheRoom = () => new Promise(cleanTheRoom);
const logStatus = end => value => {
let text = '';
if (end){
text += "at the end ";
}
text += "the room is " + value;
console.log(text);
};
retryPromiseMaker(promiseToCleanTheRoom, logStatus(false))(4)
.then(logStatus(true),logStatus(true));
I am new to Nodejs and first time working on promises so now the context is when I try to return promise it shows status Promise . How to fix it can anyone guide me through this?
Here is the code where I am calling a function that will return a promise. bold line showing where I want to return that promise and store in an object.
for(let i = 0; i<responseArray.length; i++){
let dollar = {
amount : 0
};
if(i == 1){
continue;
}
dollar.amount = **currenciesService.getCurrencyLatestInfo(responseArray[i].currency);**
dollarAmount.push(dollar);
}
console.log("$", dollarAmount);
Here is a code which is returning promise.
const getCurrencyLatestInfo = function(currency) {
return new Promise(function(resolve, reject) {
request('https://min-api.cryptocompare.com/data/price?fsym='+currency+'&tsyms='+currency+',USD', { json: true }, (err, res, body) =>
{
if (err) {
reject(err);
} else {
var result= body;
resolve(result);
console.log("RESULT: ",result.USD);
}
});
})
}
You'll need to wait for those promises to resolve before you can use the resolved values
here is a small rewrite of your loop that should work
let promises = [];
for(let i = 0; i<responseArray.length; i++){
if(i == 1){
continue;
}
let dollar = currenciesService.getCurrencyLatestInfo(responseArray[i].currency)
.then(amount => ({amount})); // do you really want this?
promises.push(dollar);
}
Promise.all(promises)
.then(dollarAmount =>console.log("$", dollarAmount))
.catch(err => console.error(err));
This should result in an array like [{amount:123},{amount:234}] as your code seems to expect
The above can also be simplified to
Promise.all(
responseArray
.filter((_, index) => index != 1)
.map(({currency}) =>
currenciesService.getCurrencyLatestInfo(currency)
.then(amount => ({amount})) // do you really want this?
)
)
.then(dollarAmount =>console.log("$", dollarAmount))
.catch(err => console.error(err));
Note: your original code suggests you want the results to be in the form {amount:12345} - which seems odd when you want to console.log("$", ....) ... because the console output would be something like
$ [ { amount: 1 }, { amount: 0.7782 } ]
given two results of course - can't see your responseArray so, am only guessing
var verifyEmail = function (thisEmail){
return new Promise(
function (resolve, reject) {
quickemailverification.verify(thisEmail, function (err, response) {
// Print response object
console.log(response.body);
if (response.body["success"] == "true"){
var validity = response.body["result"];
if (validity == "valid"){
console.log("Email Valid!");
resolve(validity);
} else {
console.log("Email Invalid!")
resolve(validity);
}
} else {
var reason = new Error("API unsuccessful");
reject(reason);
}
});
}
);
};
var saveValidity = function (validity){
return new Promise(
function (resolve, reject){
if (validity == "valid"){
var state = true;
admin.database().ref("/users_unverified/"+keys[i]+"/emails/"+x+"/verified/").set(state, function(error) {
if (error) {
console.log("Email ("+thisEmail+") verfication could not be saved" + error);
}
console.log("Email verification saved: " +thisEmail);
});
} else {
state = false;
admin.database().ref("/users_unverified/"+keys[i]+"/emails/"+x+"/verified/").set(state, function(error) {
if (error) {
console.log("Email ("+thisEmail+") verfication could not be saved" + error);
}
console.log("Email verification saved: " +thisEmail);
});
}
}
);
};
admin.database().ref("/users_unverified/").once('value').then(function(snapshot) {
var snap = snapshot.val();
keys = Object.keys(snap);
for (var i = 0; i < 100; i++){
var emails = snap[keys[i]]["emails"];
if (emails){
for (var x = 0; x<emails.length; x++){
var thisEmail = emails[x]["email"];
var emailVerified = emails[x]["verified"];
if (emailVerified != true || emailVerified != false){
verifyEmail
.then(saveValidity)
.then(function (fulfilled) {
console.log(fulfilled);
})
.catch(function (error){
console.log(error.message);
});
}
}
}
}
});
Above is the code I put together. I'm not all too convinced that it will work. I'm new to promises, so I'm trying to understand how to do this right.
The verifyEmail function should take in the email address from the firebase query in the third chunk of the code. The saveValidity function should take on the validity response from verifyEmail.
But, what I'm also worried about the nested for loop I have in the firebase query block. I'm looping through each user to validate their emails, but each user sometimes also has multiple emails. I'm worried that it will loop on to the next user before finishing checking all the emails of the previous user.
I'm also not sure if I can pass data into the promise functions the way I did.
Could definitely use some help here. Really trying hard to understand how this works.
First, you need to fix saveValidity() to always resolve or reject the promise and to pass in the other variables key and thisEmail that it references:
const saveValidity = function (validity, key, thisEmail){
return new Promise(
function (resolve, reject){
if (validity == "valid"){
let state = true;
admin.database().ref("/users_unverified/"+key+"/emails/"+x+"/verified/").set(state, function(error) {
if (error) {
let msg = "Email ("+thisEmail+") verfication could not be saved" + error;
console.log(msg);
reject(new Error("Email ("+thisEmail+") verfication could not be saved" + error));
} else {
resolve("Email verification saved: " +thisEmail);
}
});
} else {
state = false;
admin.database().ref("/users_unverified/"+keys[i]+"/emails/"+x+"/verified/").set(state, function(error) {
if (error) {
let msg = "Email ("+thisEmail+") verfication could not be saved" + error;
console.log(msg);
reject(new Error(msg));
} else {
resolve("Email verification saved: " +thisEmail);
}
});
}
}
);
};
Then, several changes are made to your main loop:
I assume we can run all the verifyEmail() calls in parallel since they don't appear to have anything to do with one another.
Change verifyEmail.then(...) to verifyEmail(thisEmail).then(...)` to actually call the function
Collect all the verifyEmail() promises in an array
Call Promise.all() on the array of promises to monitor when they are all done
Return value from .then() so we get the returned values in Promise.all()
rethrow in .catch() so promise stays rejected and will filter back to Promise.all(). You could eat errors here if you want to ignore them and continue with others.
Switch from var to let
Change from != to !== since it looks like your explicitly looking for a true or false value and don't want type casting.
Pass in the variables that saveValidity() needs.
Change logic when comparing emailVerified because what you had before was always true and thus probably not the right logic. I think what you want is to know when emailVerified is not yet set to true or to false which means you have to use &&, not ||.
Compare outer for loop with keys.length, not hard-coded value of 100.
And, here's the resulting code for the main nested for loop:
admin.database().ref("/users_unverified/").once('value').then(function(snapshot) {
let snap = snapshot.val();
let keys = Object.keys(snap);
let promises = [];
for (let i = 0; i < keys.length; i++){
let key = keys[i];
let emails = snap[key]["emails"];
if (emails){
for (let x = 0; x < emails.length; x++) {
let currentKey = key;
let thisEmail = emails[x]["email"];
let emailVerified = emails[x]["verified"];
if (emailVerified !== true && emailVerified !== false){
promises.push(verifyEmail(thisEmail).then(validity => {
return saveValidity(validity, currentKey, thisEmail);
}).then(function (fulfilled) {
console.log(fulfilled);
return fulfilled; // after logging return value so it stays the resolved value
}).catch(function (error) {
console.log(error.message);
throw error; // rethrow so promise stays rejected
}));
}
}
}
}
return Promise.all(promises);
}).then(results => {
// all results done here
}).catch(err => {
// error here
});
If ES2017 is available in your case, you can just use the keywords await and async to do that directly. Following is an example:
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
And you can read more about async/await here.
If you want to do that without async/await to achieve better browser compatibility, you can use Babel to do the pre-compile.
If you really want a lightwight implementation, you can use a function named chainPromiseThunks, or chain for short. This chain function accepts an Array of Thunks of Promises, And returns a new Thunk of Promise, Following is an one-line-implementation of chain:
const chain = thunks => thunks.reduce((r, a) => () => r().then(a));
And here is a usage demo:
const echo = x =>
new Promise(function(resolve) {
return setTimeout((function() {
console.log(x);
return resolve(x);
}), 1000);
})
;
const pThunks = [1,2,3,4,5].map(i => () => echo(i));
chain(pThunks)();
coming from a php background, I'm trying to get my head around this callback stuff.
Basically I wanna get some rows, then I would like to loop through these rows and check them against an other model (different db). I want the call back to wait until they all have been looped through and checked.
The callback gets called before sequelize has looped through all the results.
Basically I want the function to be 'blocking'. What do I have to change?
toexport.getlasttransactions = function(lower,upper,callback){
var deferred = Q.defer();
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
_.each(poenixTrx, function(value, index){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
})
.catch(function(err) {
console.log(err)
})
})
deferred.resolve(transactionsToUpdate);
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
deferred.promise.nodeify(callback);
return deferred.promise;
}
You have a lot of patterns new promise users have in your code:
You're using a deferred when you don't need to.
You're not using promise aggregation methods
You're not waiting for things in appropriate places but nesting instead.
Promises represent a value over time. You can use promises and access their result via then at a later point and not just right away - Sequelize's promises are based on bluebird and offer a rich API that does aggregation for you.
Here is an annotated version of cleaned up code - note it is not nesting:
toexport.getlasttransactions = function(lower,upper){ // no need for callback
var lowerbound = (lower || moment.utc().subtract(10, 'minutes')).format();
var upperbound = (upper || moment.utc()).format();
// use `map` over a `each` with a push.
var failedIds = FailedSync.find({ limit: 100 }).map(function(value){
return value.transaction_id;
});
// build condition.
var queryCondition = {
where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3
};
var query = failedIds.then(function(ids){ // use promise as proxy
if(ids.length === 0) return queryCondition;
return { // You can return a value or a promise from `then`
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or({ id: ids});
};
});
var pheonixTransactions = query.then(function(condition){
return PhoenixTransaction.findAll(queryCondition); // filter based on result
});
return pheonixTransactions.map(function(value){ // again, map over each
return Transaction.findOne({ where: { id: value.id }}); // get the relevant one
}).filter(function(result){ // filter over if chain and push
return (!result || result.length === 0) ||
((result && result.length === 1) && result.hash != value.hash);
});
};
Ideally you'll want to either use something like Bluebird's reduce with an array of promises, but I'll provide an async.series implementation as its easier to understand.
Install async
npm install async
Require it in your file
var async = require('async')
Then implement it as such:
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
var queryArray = poenixTrx.map(function(value){
return function(callback){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
// trigger callback with any result you want
callback(null, result)
})
.catch(function(err) {
console.log(err)
// trigger error callback
callback(err)
})
}
})
// async.series will loop through he queryArray, and execute each function one by one until they are all completed or an error is thrown.
// for additional information see https://github.com/caolan/async#seriestasks-callback
async.series(queryArray, function(err, callback){
// after all your queries are done, execution will be here
// resolve the promise with the transactionToUpdate array
deferred.resolve(transactionsToUpdate);
})
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
The whole thing is a little messy to be honest. Especially the promise/callback mix up will probably cause you problems at some point. Anyway you use the deferred.resolve on the transactionsToUpdate which is just an array so it calls the callback right away.
If you keep that script as it is use instead of _.each something like async (https://github.com/caolan/async) to run your transactions in paralell and use that as callback.
It could look like this:
toexport.getlasttransactions = function(lower,upper,callback){
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
async.each(poenixTrx, function(value, next){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
next();
})
.catch(function(err) {
console.log(err)
})
}, function(err) {
//Return the array transactionsToUpdate in your callback for further use
return callback(err, transactionsToUpdate);
});
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
}
Which would be the way with a callback.
But you need make your mind up what you want to use: callback OR promises. Don't use both together (as in: If your method expects a callback it shouldn't return a promise or if it returns a promise it shouldn't expect a callback).
Additional if you use callback you don't want to throw errors, you just call the callback and give the error in the callback - whoever uses your method can check the error from the callback and handle it.
Hope that kinda makes sense to you, I know the whole callback and promises thing is a little strange if you come from something like php and it needs some getting used to :)
thanks for explaining the differences. I think working with promises is the way forward, because it makes the code look nicer and avoids this "callback hell".
For example:
PhoenixSyncTransactions.getlasttransactions(lastTimeSynced,null)
.then(function(res){
return PersistTransaction.prepareTransactions(res).then(function(preparedTrx){
return preparedTrx;
})
}).then(function(preparedTrx){
return PersistTransaction.persistToDB(preparedTrx).then(function(Processes){
return Processes;
})
})
.then(function(Processes){
return PersistTransaction.checkIfMultiProcess(Processes).then(function(result){
return result;
})
})
.then(function(result){
console.log('All jobs done');
})
The whole code is easier to read.