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
Related
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.
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 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.
I don't know if I'm not using the .spread method correctly while working with Bluebird promises on Sails.js models. Here's what I have:
transactionAsync('BEGIN')
.then(function() {
return Model.findOne({ id: 5) });
})
.then(function(results){
if(!results) {
return res.notFound();
}
crypto.randomBytes(24, function(err, buf) {
if(err) throw new Error(err);
var token = buf.toString('hex');
// This is where it fails
return [results, token];
});
})
.spread(function(results, token) {
// It doesn't get to log these
console.log(results, token);
...
})
...
After returning [results, token] on the second .then (inside of the crypto callback), it spits out
[TypeError: expecting an array, a promise or a thenable]
I removed the rest of the code after .spread, since it's not really relevant, and that's where execution stops before returning an error.
I just want to pass variables results and token to the function inside of .spread. What am I doing wrong?
Any help is great. Thanks.
After returning [results, token] on the second .then
That's not what you're doing. You're returning inside of the crypto callback, where it is meaningless. Neither does anybody know of this callback, nor do you actually return anything from the then callback.
The first rule of promise development is to promisify the underlying API so that you can work on pure promises.
var crypto = Promise.promisifyAll(crypto);
// or specifically:
var randomBytes = Promise.promisify(crypto.randomBytes);
Now we can follow rule 3b and actually return a (promise) result from then then callback:
…
.then(function(results) {
if (!results) {
return res.notFound();
}
return crypto.randomBytesAsync(24) // returns a promise now!
// ^^^^^^
.then(function(buf) {
var token = buf.toString('hex');
return [results, token];
});
})
.spread(function(results, token) {
console.log(results, token);
…
})
.then(function(results){
if(!results) {
return res.notFound();
}
crypto.randomBytes(24, function(err, buf) {
if(err) throw new Error(err);
var token = buf.toString('hex');
// This is where it fails
return [results, token];
});
})
is wrong. You are return int from inside the randomBytes callback, not inside the then, so your then simply returns undefined and you then try to .spread that. In order to properly wait for randomBytes, you need to create a promise for that value.
.then(function(results){
if(!results) {
return res.notFound();
}
return new Promise(function(resolve, reject){
crypto.randomBytes(24, function(err, buf) {
if(err) return reject(new Error(err));
var token = buf.toString('hex');
// This is where it fails
resolve([results, token]);
});
});
})