Hi I am trying to write this function as a promise, I know how to write async functions in es6 but in es5 I am strugling
This is wath I tried:
function getLeagueByID(sportID) {
console.log(sportID);
new Promise(function (resolve, reject) {
RulesService.getLeagueByID(sportID)
.then(function (results) {
$scope.leagueById = results.data;
getStatistics($scope.leagueById[0]);
})
.catch(function (err) {
console.log(err);
});
});
}
And how should I call this function latter?
Three notes:
Whenever you already have a promise (in this case, from RulesService.getLeagueByID) you don't need to use new Promise. Insetad, chain off the promise you already have. (More here.)
Don't swallow errors; either allow them to propagate to the caller so the caller knows what's going on, or report them (not just to the console). Only handle errors at the highest level you can, which is usually an event handler that kicked off the overall process.
You aren't returning anything from the function.
Addressing those, your function should probably look like this, which allows the caller to deal with errors:
function getLeagueByID(sportID) {
console.log(sportID);
return RulesService.getLeagueByID(sportID)
.then(function(results) {
$scope.leagueById = results.data;
getStatistics($scope.leagueById[0]); // If this returns a promise or
// value you should return, add
// `return` in front of it
});
});
}
But if you don't expect the caller to handle errors, then:
function getLeagueByID(sportID) {
console.log(sportID);
return RulesService.getLeagueByID(sportID)
.then(function(results) {
$scope.leagueById = results.data;
getStatistics($scope.leagueById[0]); // If this returns a promise or
// value you should return, add
// `return` in front of it
})
.catch(function (err) {
// Do something other than just `console.log` here, in most cases; for instance, show an
// error to the user
});
});
}
And how should I call this function latter?
That depends on what's calling the function. As with the above, if it's something that's expecting its caller to handle errors, then:
return getLeagueByID(someSportId);
If it's an event handler or similar, and so doesn't expect its caller to handle errors, then:
getLeagueByID(someSportId)
.catch(function (err) {
// Do something other than just `console.log` here, in most cases; for instance, show an
// error to the user
});
As RulesService.getLeagueByID returns a promise, you can just return that.
function getLeagueByID(sportID) {
console.log(sportID);
return RulesService.getLeagueByID(sportID)
.then(function (results) {
$scope.leagueById = results.data;
getStatistics($scope.leagueById[0]);
})
.catch(function (err) {
console.log(err);
});
}
To call it
getLeagueByID(id)
.then(function(){HANDLER CODE});
function getLeagueByID(sportID) {
console.log(sportID);
return new Promise(function (res, rej) { //you need to return here
RulesService.getLeagueByID(sportID)
.then(function (results) {
$scope.leagueById = results.data;
res(getStatistics($scope.leagueById[0])); //resolve
return; //return to avoid unintended side effects
})
.catch(function (err) {
console.log(err);
rej(err) //need to reject
return; //return to avoid unintended side effects
});
});
}
A promise is just like an async method.
To use this, you can
await getLeagueByID(sportID)
in an async method, or you can use
getLeagueByID(sportID).then(r=>console.log(r)).catch(e=>console.log(e))
essentially 'forking' the current thread.
Related
pardon me for asking such a beginner level question, because I not satisfied with answers titled with same question. Basically I need a promise return type for my function after performing some packages function which also returns promise.
myquest.js
module.exports = somefunction = (data){
//performs some processing with data
somePackagePromiseFunc() //return type promise
.then((data) => {
console.log(data);
return new Promise.resolve(data);
}).catch( (err) => {
console.log(err);
return new Promise.reject(err);
});
}
mymain.js
var somefunction = require('myquest');
somefunction(data).then((data) => {
console.log('job done with data ' + data);
}).catch(() => {
console.log('we messed with error: ' + err);
})
Help me to understand my mistake.
The simplest fix to your code is
Fix the syntax in the first line
return something, in this case a Promise, in that function
is somePackagePromiseFunc a function? then call it
fix the return value in .then/.catch
You'll end up with
module.exports = function (data) {
//performs some processing with data
return somePackagePromiseFunc().then((data) => {
console.log(data);
return data;
}).catch( (err) => {
console.log(err);
throw err;
});
}
Note about some of your code:
return new Promise.resolve(data);
Promise.resolve is not a constructor, so remove new would make it
return Promise.resolve(data);
However, you're inside a .then, whatever you return is a Promise that resolves the the value returned in .then - so, no need to wrap it in Promise.resolve at all - so that's why you only need
return data;
Similarly for .catch, except to return a rejected promise, you throw instead of return - though technically you can
return Promise.reject(err);
Note, no "new", because it's also not a constructor
I try to figure out how to proper handle errors in promise chain. There are few promises and one of them throws error. In case of error I would like to terminate function in chain.
The issues I faced with are:
How can we terminate next call from catch block?
How to guarantee execution order then().catch().then() chain? At this
moment I observe catch block is called after execution of both then() functions.
Code sample:
function run() {
test().then(function(data) {
console.log("w3", "Print data: " + data);
});
}
function test() {
return new Promise(function(fulfill, reject) {
ask()
.catch(err => console.log("w3", "Process error from ask: " + err))
.then(reply())
.catch(err => console.log("w3", "Process error from reply: " + err))
.then(function(data) {
console.log("w3", "Finish test");
fulfill(data);
// TODO finish data
})
});
}
function ask() {
return new Promise(function(fulfill, reject) {
console.log("w3", "ask");
// fulfill("Hello");
reject("Cancel Hello");
});
}
function reply() {
return new Promise(function(fulfill, reject) {
console.log("w3", "reply");
fulfill("World!");
// reject("Cancel World");
});
}
That's not how Promise chains work. Promises will only chain correctly if you explicitly return a Promise out of every function invoked in your .then() blocks. If you don't return a Promise out of these functions, the next .then() block is immediately invoked.
You probably want to do something like this:
function run() {
test()
.then(function (data) {
console.log("w3", "Print data: " + data);
});
}
function test() {
return ask()
.then(function (result) {
return reply();
})
.then(function (data) {
console.log("w3", "Finish test");
return Promise.resolve(data);
})
.catch(function (error) {
console.log("Hey an error was thrown from somewhere");
if(error instanceof UnexpectedAskError) {
//handle specific error logic here.
}
});
}
function ask() {
console.log("w3", "ask");
return Promise.reject(new UnexpectedAskError("Ask threw an error"));
}
function reply() {
console.log("w3", "reply");
return Promise.resolve("World!");
}
Notice how the ask function returns a specific type of error? You can do something like that if you need to perform different error handling based on which function threw an error.
To specifically answer the questions you asked:
The above method of chaining promises will prevent the next .then() being called if an error is thrown by the previous function.
The above method of chaining will ensure that your .then() blocks are called in the order specified. As long as every .then() is a function, and every function returns a Promise, either through constructing a new Promise(function(resolve, reject)) or through Promise.resolve or Promise.reject, the chain will execute in the correct order.
You just catch at the end of the chain. If there's any error. It will ignore the other then and go direct to catch.
function test() {
return new Promise(function(fulfill, reject) {
ask()
.then(reply())
.then(function(data) {
console.log("w3", "Finish test");
return fulfill(data); // <= Make sure to return here
// TODO finish data
})
.catch(err => console.log("w3", "Process error from reply: " + err))
});
}
Make sure to return Promise or else it won't catch your error.
fulfill(data); should be return fulfill(data);
I'm having trouble understanding the output printed why executing this code :
1
2
Unhandled rejection Error: Callback was already called.
It seems like both then and catch are executed when the query is successful.
Any idea ?
Cheers
async.series([
function(callback) {
db.none(query)
.then(function () {
return callback(null, true);
})
.catch(function (err) {
return callback(err, null);
});
},
function(callback) {
db.any(query)
.then(function (data) {
console.log('1')
return callback(null, data);
})
.catch(function (err) {
console.log('2')
console.log(err);
return callback(err, null);
});
}
],
function(err, results) {
if (results && !results[1].isEmpty()) {
// do something
}
});
EDIT :
TypeError: results[1].isEmpty is not a function
It seems like the problem come from the rest of the code and was just a simple undefined function error, thanks.
But i still don't understand something : why is this error catched inside the second query instead of outside the async queries ?
I'm the author of pg-promise.
You should never use async library with pg-promise, it goes against the concept of shared/reusable connections.
Implementation with proper use of the same connection, via a task:
db.task(t => {
return t.batch([
t.none(query1),
t.any(query2)
]);
})
.then(data => {
// data[0] = null - result of the first query
// data[1] = [rows...] - result of the second query
callback(null, data); // this will work, but ill-advised
})
.catch(error => {
callback(error, null); // this will work, but ill-advised
});
See also: Chaining Queries.
However, in your case it looks like when you call the successful callback(null, data), it throws an error, which in turn results in it being caught in the following .catch section. To test this, you can change your promise handler like this:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
});
It should normally throw an error about Promise missing .catch because you threw an error while in .then and there is no corresponding .catch chained below, which you can also check through this code:
.then(data => {
callback(null, data);
}, error => {
callback(error, null);
})
.catch(error => {
// if we are here, it means our callback(null, data) threw an error
});
P.S. You really should learn to use promises properly, and avoid any callbacks altogether. I only provided an example consistent with your own, but in general, converting promises into callbacks is a very bad coding technique.
This is what happens:
callback(null, data) is called within the context of the .then();
async notices that this was the last item of the series, so it calls the final handler (still within the context of the .then());
the final handler throws an error;
because the code runs in the context of .then(), the promise implementation catches the error and calls the .catch();
this calls the callback again;
PoC:
const async = require('async');
async.series([
callback => {
Promise.resolve().then(() => {
callback(null);
}).catch(e => {
callback(e);
});
}
], err => {
throw Error();
})
Have you try to define your function externally:
function onYourFunction() {
console.log('Hi function');
}
and than do:
.then(onYourFunction) //-->(onYourFunction without parentheses )
Unfortunately i don't use pg-promise but i can advise promise
at this point i create all promises that are necessary:
function createPromise(currObj) {
return new Promise(function (resolve, reject) {
currObj.save(function (errSaving, savedObj) {
if(errSaving){
console.log("reject!");
return reject(errSaving, response);
}
console.log('currObj:' + currObj);
return resolve(savedObj);
});
});
}
and then in cascades:
var allPromiseOs = Promise.all(promise1, promise2, promise3);
I am programming a new promise, it has many different conditions that call reject() or resolve() related to their state, also I know that the promise state will set with the first call to reject() | resolve().
My question is:
Is there any native (build-in) way to get the promise state?
The following is a demonstrative-code:
exports.addStatement = function (db, description, data) {
return new Promise(function (resolve, reject) {
validator.validateStatement(description, data)
.then(function (data) {
//......
if(cnd1)
resolve(res);
if(cnd2)
reject(err);
//......
//How to check if this promise is rejected or resolved yet?
})
.catch(function (err) {
reject(err);
})
})
};
You cannot directly examine the state of a promise. That's not how they work. You can use .then() or .catch() on them with a callback to get notified.
Or, in your specific case, you can probably change the way your code is structured to remove the anti-pattern of creating an unnecessary outer promise and switching your logic to if/else if/else.
Here's the cleaned up code:
exports.addStatement = function (db, description, data) {
return validator.validateStatement(description, data)
.then(function (data) {
//......
if(cnd1) {
// make res be the resolved value of the promise
return res;
} else if(cnd2) {
// make promise become rejected with err as the reason
throw err;
} else {
// decide what else to do here
}
})
})
};
If you couldn't make an if/else work for you, the above structure should still work because both the return and the throw terminate the execution of the .then() handler. So, the only code that continues after them is code that has not yet set the resolved/rejected value for the current promise so you don't have to look at the state of the promise to know that. If the code gets past the return and throw and is still executing, then neither of those was executed and the resolved/rejected value of the current promise is still unset.
I have following code in my node.js file;
GameHelperAuth.prototype.GetUserViaApi = Promise.method(function (authCookie, callback) {
// get user from API
});
GameHelperAuth.prototype.GetObjectFromCache = Promise.method(function (authCookie, callback) {
// get user from Cache
});
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
// check cache
this.GetObjectFromCache()
.then(function (result) {
if (result) {
return callback(null, result);
}
else {
// not found in cache, get it from API
// **NOT WORKING HERE - undefined error**
this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
I would like to access my instance method from another instance method once promise is completed. But it looks like it loses it's context and cannot find function anymore. (Please see where I am calling GetUserViaApi method)
Is there any way for me to reach that method without creating new instance of my class?
As far as I can see, the simplest fix here is to just declare var self = this in the first line of .GetUser() and then use self instead of this inside the .then callback.
Alternatively if you're using Node 4+ with ES6 compatibility, use an "arrow function" as the outer .then callback that inherits the lexical this instead of contextual this:
return this.GetObjectFromCache()
.then((result) => {
if (result) {
return callback(null, result);
} else {
// not found in cache, get it from API
return this.GetUserViaApi(authCookie)
.then(function (apiResult) {
return callback(null, apiResult);
}).catch(function (err) {
throw err;
});
}
})
.catch(function (err) {
throw err;
});
NB: note the addition of the return in the first line and in the else clause, necessary to ensure that the function and that branch both correctly return a promise.
FWIW, I also think you can refactor this substantially by eliminating the repeated call to return callback(...) through a chaining .then:
GameHelperAuth.prototype.GetUser = function (authCookie, callback) {
return this.GetObjectFromCache()
.then(result => result || this.GetUserViaApi(authCookie))
.then(result => callback(null, result));
}
I've removed both .catch blocks - doing .catch(function(err) { throw err }) is a no-op - AIUI the throw would make the caller end up in their own .catch block so you might just as well let the entire promise reject anyway.