I am struggling with promises
having the following snippet:
Promise.resolve()
.then(a("OK1"))
.then(a("OK2"))
.then(a("OK3"))
.then(a("OK4"))
.then(a("OK5"))
.then(function() {
console.log("FINISH");
})
.catch(function(e) {
console.log("ERROR: " + e);
});
function a(i) {
return new Promise(function(resolve, reject) {
if(i == "OK4") {
console.log("THROW");
throw('Error'); //This does not happen
reject();
return;
}
if(i == "OK2") {
reject()
return;
}
console.log(i);
resolve();
});
}
i want to be able to reject a promise - then the next .then is executed ("OK3")
but i am unable to throw exceptions - i want to trigger the .catch on "OK4"
OK4 - is rejected and not outputted, but OK5 still gets executed - is there a way arround it?
this would be my expected output:
OK1
OK3
ERROR: ....
As Bergi mentioned, the parameter you are passing on each .then runs the function immediately and return a promise. The promise chain needs a reference to a function it can run at a later date.
If you want to run your function with a parameter, you can wrap it in an anonymous function so the promise chain can run the anonymous function at a later time.
a("OK1")
.then((res)=>{
return a("OK2")
})
.then((res)=>{
return a("OK3")
})
.then((res)=>{
return a("OK4")
})
.then((res)=>{
return a("OK5")
})
.then(()=>{
console.log("FINISH");
})
.catch(function(e) {
console.log("ERROR: " + e);
});
function a (i) {
return new Promise(function(resolve, reject) {
if(i == "OK4") {
console.log("THROW");
throw new Error(i); //This does not happen
}
if(i == "OK2") {
return reject(new Error(i))
}
setTimeout(function () {
console.log(i);
resolve(i);
}, 100)
});
}
It is ok to pass a function that will eventually return a promise. The function will be passed the value that the previous promise resolved with.
b(1)
.then(b)
.then(b)
.then(b)
.then((res) => {
console.log("FINISH",res);
})
.catch(function (e) {
console.log("ERROR: " + e);
});
function b (i) {
return new Promise(function (resolve, reject) {
console.log(i)
resolve(i+1)
})
}
Related
im trying to write a promise but seems to be missing something. here is my code:
const myPromise = new Promise(() => {
setTimeout(() => {
console.log("getting here");
return setinputs({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then(() => {
console.log("getting here too");
firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
if i run the program, the first part of the promise is executing but all .then() functions arent executing. how do i fix this?
In this scheme, the promise callback has one (resolve) or two (resolve,reject) arguments.
let p = new Promise((resolve, reject)=> {
//do something
//resolve the promise:
if (result === "ok") {
resolve(3);
}
else {
reject("Something is wrong");
}
});
p.then(res => {
console.log(res); // "3"
}).catch(err => {
console.error(err); //"Something is wrrong
});
Of course, nowadays you can use async + await in a lot of cases.
You need to resolve the promise, using resolve() and also return the promise from firebase so the next .then in the chain works properly.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("getting here");
// You have to call resolve for all `.then` methods to be triggered
resolve({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then((inputs) => {
console.log("getting here too");
// You have to return a promise in a .then function for the next .then to work properly
return firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
I have a chain of promises as a function in my app. Each of my service functions returns a deferred.promise;
Considering the following scenario I have where main getUser service calls getUserPreferences and getUserFavourites asynchronously, the console.log after resolving getUserData is being resolved before getUserFavourites even responds! Shouldn't the promise in getUserData be resolved once getUserFavourites responds?
In fact 'got all user data' from the console.log is in the console before getUserFavourites is called. Literally straight after getUser responds almost like getUserData().then( only resolves the top level promise and make the underlying 2 asynchronous...
What am I doing wrong here?
var user = 'blabla';
function getUserData() {
var deferred = $q.defer();
getUser(user).then(
function(response) {
getUserPreferences(response.user).then(
function(preferences) {
console.log('preferences', preferences);
},
function() {
deferred.reject();
}
);
getUserFavourites(response.user).then(
function(favourites) {
deferred.resolve();
console.log('favourites', favourites);
},
function() {
deferred.reject();
}
);
},
function() {
deferred.reject();
}
);
return deferred.promise;
}
getUserData().then(
function() {
console.log('got all user data');
}
);
A way to fix that is to use the async/await to make the code look synchronous.
var user = 'blabla';
async function getUserData() {
try {
var deferred = $q.defer();
let userInfo = await getUser(user)
let userPrefs = await getUserPreferences(userInfo.user)
console.log('preferences', userPrefs);
let userFavourites = await getUserFavourites(userInfo.user)
deferred.resolve();
console.log('favourites', userFavourites);
return deferred.promise;
} catch (error) {
deferred.reject();
}
}
getUserData().then(
function() {
console.log('got all user data');
}
);
Use $q.all to return a composite promise:
function getUserData() {
return getUser(user).then(function(response) {
var preferencesPromise = getUserPreferences(response.user);
var favouritesPromise = getUserFavourites(response.user);
return $q.all([preferencesPromise, favouritesPromise]);
});
}
Then extract the data from the composite promise:
getUserData().then([preferences, favourites] => {
console.log('got all user data');
console.log(preferences, favourites);
}).catch(function(error) {
console.log(error);
});
The $q.all method returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.
For more information, see
AngularJS $q Service API Reference - $q.all
You must RETURN the nested promise in order to have a chain.
The problem here is you have 2 nested promises so you will need to return a Promise.all (or $q.all in your case) taking an array of the 2 promises returned by getUserPreferences and getUserFavorites:
var user = 'blabla';
function getUserPreferences(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser().then(
function(user) {
console.log(user);
var prefPromise = getUserPreferences(user).then(
function(preferences) {
console.log('preferences', preferences);
return preferences;
},
function(error) {
console.log("Error getting preferences");
throw error;
}
);
var favPromise = getUserFavorites(user).then(
function(favourites) {
console.log('favourites', favourites);
return favourites;
},
function(error) {
console.log("Error getting favorites");
throw error;
}
);
return Promise.all([
prefPromise,
favPromise
]);
},
function(err) {
console.log("Error getting user");
throw err;
}
);
}
getUserData().then(
function(results) {
console.log(results);
}
);
Note that for demo purpose I am using es6 Promise instead of angular $q but the spirit is the same:
$q.defer() => new Promise()
$q.all => Promise.all
As the Promise pattern is great to simplify async code and make it look like synchronous code, you can simplify the upper example with something like:
var user = { name: 'blabla'};
function getUserPreferences(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser()
.then(user => { // user is resolved
// running parallel promises to get user infos:
return Promise.all([
user,
getUserPreferences(user),
getUserFavorites(user)
]);
})
.then(results => {
// wrapping the results into something more semantic:
let userData = results[0];
userData.prefs = results[1];
userData.favs = results[2];
return userData;
});
}
getUserData().then(
function(userData) {
console.log('Final result:');
console.log(userData);
}
);
In this simplified example, I am calling three functions when the first promise gets resolved.
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
test.then( () => { console.log("A") });
test.then( () => {
return new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 3000)
});
});
test.then( () => { console.log("B") });
The output as expected is A B C.
Let's suppose that I want to invoke the third .then to console B only when the second promise gets resolved.
If I try to store the second promise (myProm) in global and attach a .then function on it, I'll get (reasonably) a TypeError because at compile time myProm is still undefined.
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
var myProm;
test.then( () => { console.log("A") });
test.then( () => {
myProm = new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 3000)
})
return myProm;
});
myProm.then( () => { console.log("B") });
How do I proceed? What's the best way to chain two promises together so that the returned Promise obj from one .then needs to get resolved before we can execute the next then.
In this scenario, the output I'd like to have would be A C B
then returns a promise that resolves when the indicated function has run and the value it returned has resolved (this is a slight oversimplification, but sufficient for the task here).
Therefore, to chain a promise on the result of a then. Just tack on another .then:
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
test.then( () => { console.log("A") });
test
.then( () => {
return new Promise(function(res, err) {
setTimeout(()=> { console.log("C"); res() }, 3000);
});
})
.then( () => { console.log("B") });
Each time you call .then, you create a new Promise that resolves when the Promise returned by that .then resolves. You should assign the result of the myProm-containing .then to a variable, and then call .then on that variable:
var test = new Promise(function (res, err) { setTimeout(res, 500) })
var myProm;
test.then( () => { console.log("A") })
.then( () => {
myProm = new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 500)
})
return myProm;
})
.then( () => { console.log("B") });
Most of the time when using Promises, you should be chaining .thens like this. Only do prom.then(...) ... prom.then(...) when you want to initialize two completely separate asynchronous operations when the prom resolves.
I currently try to use two kind of promises. One for the overall convensation, and one to get the userids to usernames.
The code works when its ran first time, and is looking something like this:
The output above is what i wanted.
But when i run the query again, i get this:
what is wrong with my code? what do i need to do to make the promises go correctly?
code:
function getconvensations(userid) {
return new Promise(function(resolve, reject) {
convensations.find({members: userid}).lean().then(function (convensations) {
var promises = convensations.map(function (currentConvensation) {
return new Promise(function (resolve, reject) {
var realnames = [];
var usernames = currentConvensation.members.map(function (CurrentUser) {
Core.userDetails(CurrentUser).then(function (user) {
realnames.push(user.username);
console.log("RESOLVING USERNAMES");
resolve();
});
});
Promise.all(usernames).then(function () {
console.log("GET LATEST MESSAGE");
latestMessage(currentConvensation._id).then(function (message) {
console.log("Messages: ");
console.log(message);
currentConvensation.spesificmessage = message;
currentConvensation.users = realnames;
currentConvensation.otherend = (currentConvensation.members[0] == userid ? realnames[0] : realnames[1]);
console.log("RESOLVE LATEST MESSAGE");
resolve();
});
});
});
});
Promise.all(promises).then(function () {
console.log("FINISHED CONVENSATIONS");
console.log("-------------------------");
console.log(convensations);
console.log("-------------------------");
return resolve(convensations);
}).catch(console.error);
});
});
}
caller:
} else if(action == 'getconvensations') {
Messages_model.getconvensations(req.user._id).then(function (response) {
res.json(response);
});
}
You have a race condition here:
new Promise(function (resolve, reject) {
…
currentConvensation.members.map(function (CurrentUser) {
Core.userDetails(CurrentUser).then(function (user) {
resolve();
});
});
…
latestMessage(currentConvensation._id).then(function (message) {
resolve();
});
…
});
There are arbitrarily many tasks executing concurrently, and the first promise that fulfills will call resolve().
The solution is to avoid the Promise constructor antipattern and never ever call new Promise or resolve manually! Instead, chain promise callbacks to each other using the then method, and return new promises from every function to allow the caller to wait for them.
function getconvensations(userid) {
return convensations.find({members: userid}).lean().then(function (convensations) {
// ^^^^^^
var promises = convensations.map(function (currentConvensation) {
var usernamepromises = currentConvensation.members.map(function (CurrentUser) {
console.log("GETTING USERNAME");
return Core.userDetails(CurrentUser).then(function (user) {
// ^^^^^^
console.log("FULFILLED USERNAME");
return user.username;
// ^^^^^^
});
});
return Promise.all(usernamepromises).then(function (realnames) {
// ^^^^^^
console.log("FULFILLED ALL USERNAMES");
currentConvensation.users = realnames;
currentConvensation.otherend = (currentConvensation.members[0] == userid ? realnames[0] : realnames[1]);
console.log("GETTING LATEST MESSAGE");
return latestMessage(currentConvensation._id);
// ^^^^^^
}).then(function (message) {
console.log("FULFILLED LATEST MESSAGE");
console.log("Message: ", message);
currentConvensation.spesificmessage = message;
});
});
return Promise.all(promises).then(function () {
// ^^^^^^
console.log("FINISHED ALL CONVENSATIONS");
console.log("-------------------------");
console.log(convensations);
console.log("-------------------------");
return convensations;
// ^^^^^^
});
});
}
I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
function promiseFunc(options) {
return new Promise(() => {
return options;
});
}
function myfunc(options) {
return new Promise(() => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then((result) => {
if (result.throwerr) throw new Error("thrown on purpose");
return result.value;
});
});
};
My test as follows:
const myfunc = require("./myfunc");
describe('myfunc', () => {
it('should fail without options', () => {
return myfunc()
.then((result) => { throw new Error(result) }, (err) => {
console.log("test #1 result:", err.message === "missing options");
});
});
it('should fail on options.throwerr', () => {
return myfunc({throwerr: true})
.then((result) => {}, (err) => {
console.log("test #2 result:", err.message === "thrown on purpose");
});
});
it('should return options.value', () => {
return myfunc({value: "some result", throwerr: false})
.then((result) => {
console.log("test #3 result:", result === "some result");
}, (err) => {});
});
});
The first test pass, but the second and third fails.
Log #2 does not even run, so I assumed the "throw on purpose" messes up something, therefore I created test #3, where I don't throw anything, but it still fails.
What am I missing?
Solution:
function promiseFunc(options) {
return new Promise(resolve => {
return resolve(options);
});
}
function myfunc(options) {
return new Promise((resolve, reject) => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then(result => {
if (result.throwerr) throw new Error("thrown on purpose");
return resolve(result.value);
}).catch(err => {
return reject(err);
});
});
};
You forgot to pass a function with resolve and reject parameters, so your promises just don't work.
function promiseFunc(options) {
return new Promise(resolve => { // resolve function
resolve(options)
})
}
module.exports = function myfunc(options) {
return new Promise((resolve, reject) => { // since you may either resolve your promise or reject it, you need two params
if (!options) {
return reject(new Error("missing options"))
}
return promiseFunc(options).then(result => {
if (result.throwerr) {
return reject(new Error("thrown on purpose"))
}
resolve(result.value)
})
})
}
... and the test (mocha)
const assert = require('assert'),
myfunc = require("./myfunc")
describe('myfunc', () => {
it('should fail without options', done => { // mind the callback, promises are always async
myfunc()
.catch(err => {
assert(err.message === "missing options")
done() // <- called here
})
})
it('should fail on options.throwerr', done => {
myfunc({throwerr: true})
.catch(err => {
assert(err.message === "thrown on purpose")
done()
})
})
it('should return options.value', done => {
return myfunc({value: "some result", throwerr: false})
.then(result => {
assert(result === "some result")
done()
})
})
})
I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
This will do it ...
var q = require('q'); // In recent versions of node q is available by default and this line is not required
function iReturnAPromise(num) {
var def = q.defer();
if (typeof num=== 'number') {
try {
var value = 100 / num;
def.resolve(value);
} catch(e) {
def.reject("oops a division error - maybe you divided by zero");
}
} else {
def.reject("o no its not a number");
}
return def.promise;
}
PS this function was coded freehand and has not been tested - but this will work. Obviously try catch should be used sparingly.
PS I prefer the q library implementation of promise instead of the default node promise library - they take a very different approach. q dispenses with all the wrapping!
using the promise library u wanted ...
function iReturnAPromise(num) {
return new Promise(function(resolve, reject) {
if (typeof num === 'number') {
try {
var value = 100 / num;
resolve(value);
} catch (e) {
reject("oops a division error - maybe you divided by zero");
}
} else {
reject("o no its not a number");
}
})
}
iReturnAPromise(7).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
// Unexpectedly this is not an error in node 5.6 because div by 0 is not an error operation anymore!
iReturnAPromise(0).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
iReturnAPromise("fred").then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
you can see why i prefer the q syntax :)