I'm using Promise.reject
I've got this warning: Unhandled promise rejection warning: version is not released
how can I solve this warning ? I'm trying to use try and catch
Thanks for your help
public async retrieveVersionFromJira(versionName: string):
Promise<ReleaseVersion> {
const searchVersionsUri = config.jiraApiUri + 'versions';
const jsonResp = await this.jiraClient.get(searchVersionsUri);
const version: any = jsonResp.find(version => {
if (version.name == versionName) {
if (version.released == true) {
try{
return Promise.reject("version " + versionName + " is not released");
}
catch{
return Promise.reject("error test")
}
}
}
});
if (!version) {
return Promise.reject("missing version " + versionName + " on jira");
}
return new ReleaseVersion(version.id, version.name, version.released);
}
There are probably two problems:
Not handling rejection. This problem isn't in retrieveVersionFromJira, it's in the code using it. That code needs to handle the fact that it may reject its promise. Apparently, the code using it is only handling success, not failure.
One of the basic rules of promises (and thus, async functions, which return promises) is that you must either handle rejection (errors), or pass the promise on to a calling function that will handle rejection.
If you're calling it from an async function, that function will automatically pass on rejection to its caller (which should either pass it on or handle it). If you're using a top-level async function, it needs to never reject (by using try/catch to catch all errors/rejections that occur within it), like this:
// If this is the top level
(async function() {
try {
const version = retrieveVersionFromJira("name");
// ...use `version`...
} catch {
// Handle/report error
}
})();
If you're calling it from a non-async function, that function also must either return the promise chain to its caller (which should either pass it on or handle rejection) or handler rejection, e.g.:
// Pass it on
function someFunction() {
return retrieveVersionFromJira("name")
.then(version => {
// ...use the result...
});
}
// Or handle rejection
function someFunction() {
retrieveVersionFromJira("name")
.then(result => {
// ...use the result...
})
.catch(error => {
// Handle/report the error
});
}
The code in retrieveVersionFromJira calling jsonResp.find is incorrect. You've said that jsonResp is an array¹. Array.prototype.find expects the callback to return a truthy or falsy value indicating whether the current entry is the one you want to find. Your code attempts to return from retrieveVersionFromJira from within the callback, which it can't do. You also have if (version.released == true) followed by return Promise.reject("version " + versionName + " is not released");, which doesn't seem to make sense. You probably wanted:
const version: any = jsonResp.find(version => version.name === versionName);
if (version && !version.released) {
return Promise.reject("version " + versionName + " is not released");
}
...but see the note under the line below about return Promise.reject(...) not being the best way to handle rejecting the promise from an async function.
¹ ...in which case, it isn't JSON. JSON is a textual notation for data exchange. If you're dealing with JavaScript source code, and not dealing with a string, you're not dealing with JSON.
Side note: Although it isn't the problem, the code in retrieveVersionFromJira shouldn't be using Promise.reject. See this question's answers, the way to reject the promise from an async function is to use throw. Everywhere you've used return Promise.reject(x); you should be using throw x;. Also, since rejections are errors, it's usually best to use Error instance (e.g., throw new Error("missing version " + versionName + " on jira");.
Related
I am new to typescript / javascript, so I don't know much about promises. Here is my use-case: I am creating three different promises inside my cloud-function and then returning it with Promise.all([promise1, promise2, promise3]). Each of these promises are created inside a function with "return Promise...".
My question is, when I add ".catch" inside these functions, will Promise.all still work?. Does it make any difference returning someServiceThatCreatesPromise() with and without .catch()?
Code
export async function myCloudFirestoreFunction() {
try {
const myFirstPromise = createFirstPromise()
const mySecondPromise = createSecondPromise()
const thirdPromise = createThirdPromise()
return Promise.all([
myFirstPromise,
mySecondPromise,
myThirdPromise
]);
} catch (err) {
functions.logger.err(`Something bad happened, See: ${(err as Error).message}`
}
}
// Difference with and without `.catch`?
function createFirstPromise() {
return someServiceThatCreatesPromise().catch((err) => { // LOGGING });
}
// Difference with and without `.catch`?
function createSecondPromise() {
return someServiceThatCreatesPromise().catch((err) => { // LOGGING });
}
// Difference with and without `.catch`?
function createThirdPromise() {
return someServiceThatCreatesPromise().catch((err) => { // LOGGING });
}
Adding .catch inside createNPromise won't affect anything assuming all your Promises resolve and do not reject.
However, if one of the Promises rejects and you catch it within the .catch method, then it won't work as you're expecting unless you re-throw that error and catch it again inside the try/catch in your myCloudFirestoreFunction function.
async function myCloudFirestoreFunction() {
try {
const result = await Promise.all([
createFirstPromise(),
createSecondPromise()
]);
} catch (error) {
console.log({ error });
}
}
function createFirstPromise() {
return Promise.reject("Oof").catch((e) => {
// do work, e.g. log, then
// pass the error forward so that it can be caught
// inside the caller
throw e;
});
}
function createSecondPromise() {
return Promise.resolve("value");
}
myCloudFirestoreFunction();
Alternatively, you just catch errors inside the caller (myCloudFirestoreFunction) instead of catching them separately.
async function myCloudFirestoreFunction() {
const result = await Promise.all([
createFirstPromise(),
createSecondPromise()
]).catch((err) => console.log({ err }));
}
function createFirstPromise() {
return Promise.reject("Oof");
}
function createSecondPromise() {
return Promise.resolve("value");
}
myCloudFirestoreFunction();
when I add ".catch" inside these functions, will Promise.all still work?
Calling catch() on a promise does not in any way change the way the original promise works. It is just attaching a callback that gets invoked when the first promise becomes rejected, and also returning another promise that resolves after the original promise is fulfilled or rejected.
Does it make any difference returning someServiceThatCreatesPromise() with and without .catch()?
It would not make any difference to the code that depends on the returned promise. Both the original promise and the one returned by catch() will tell downstream code when the original work is done by becoming fulfilled.
I suggest reading comprehensive documentation on promises, for example:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
There is a diagram in there that you can follow to understand what happens at each turn. Also in that document, you will read:
Processing continues to the next link of the chain even when a .then() lacks a callback function that returns a Promise object. Therefore, a chain can safely omit every rejection callback function until the final .catch().
This question already has answers here:
correct way to handle errors inside a Promise
(3 answers)
Promise constructor with reject call vs throwing error
(4 answers)
Correct Try...Catch Syntax Using Async/Await
(6 answers)
Closed 4 years ago.
I am completely new to Promises and async/await and just reading through tutorials etc., so I expect I may be missing something fundamental.
I've see this code pattern in several places, but I'm thinking maybe it should not be trusted:
async function myFunc() {
try {
var result = await doSomethingAsync();
console.log(result);
}
catch(error) {
console.error(error); // hmm
}
}
myFunc();
Consider the following scenario using the above pattern:
const doSomethingAsync = behaviour => new Promise((resolve, reject) => {
// use setTimeout to simulate e.g. an async webapi callback func
setTimeout(() => {
if(behaviour === "set resolve")
resolve("resolved");
if(behaviour === "set reject")
reject("rejected");
if(behaviour === "set after timeout error")
throw new Error("something went wrong after setTimeout returned");
}, 500);
if(behaviour === "set promise error")
throw new Error("something went wrong in promise");
});
async function myFunc(behaviour) {
try {
// wait for promise to complete
var result = await doSomethingAsync(behaviour);
console.log(result);
}
catch(error) {
console.error("caught:" + error); // will catch reject and promise error,
// but NOT after setTimeout error
}
}
myFunc("set promise error"); // caught:Error: something went wrong in promise
myFunc("set resolve"); // resolved
myFunc("set reject"); // caught:rejected
myFunc("set after timeout error"); // Uncaught Error: something went
// wrong after setTimeout returned
// UHOH!!
So the pattern seems a little misleading as it cannot catch the setTimeout error, whereas people tend to think of catch() as a catch-all.
Of course, changing the setTimeout to have an internal catch will solve the uncaught error problem:
const doSomethingAsync = behaviour => new Promise((resolve, reject) => {
// use setTimeout to simulate e.g. an async webapi call
setTimeout(() => {
try { // ...
}
catch(e) { reject("an error"); }
}, 500);
});
So, my questions are:
As I understand it, Promises are used as a replacement for callbacks, i.e. for wrapping async calls like setTimeout. So should there always be an internal try/catch -> reject pattern implemented inside a Promise? (So that the error can be gracefully handled by the caller). Do e.g. all node libraries work in this way?
I can't see any way for the caller to deal with it by itself.
I find the pattern misleading, wouldn't the pattern be better like this?
async function myFunc(behaviour) {
try {
var result = await doSomethingAsync(behaviour);
.catch(e) { console.log("expected reject happened:" + e) };
}
catch(error) {
console.error("something totally unexpected happened:" + error);
}
}
I need to write a function that returns a promise, where first I call a synchronous function A() which returns some result.
Then return a function B(result) where B is a promise which takes in the result of A().
If either function fails I want the same error function C(error) to get called where C is a promise.
What is the best way of writing this. This is what I have but think there is obvious way I am missing
function() {
try {
var result = A();
return B(result)
.catch(function(error) {
return C(error);
});
}
catch(error) {
return C(error);
}
}
It seems wrong combining synchronous try and catch with a promise .catch and also wrong there are two different places I need to call C(error).
A() throws an error rather than returning an error code.
You don't say exactly how A() fails. It could either throw or it could return an error result. I'll show a scheme for both. The key to a mix of sync and async is to always return a promise. This will give you a consistent interface for teh caller no matter how the function succeeds or fails.
If you are only worried about A() throwing an exception and it doesn't return an error code, then you can do this:
function someFunction() {
try {
var result = A();
return B(result);
} catch(err) {
return Promise.reject(err);
}
}
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
If you also have the case where A() can return an error code, then you can do this:
function someFunction() {
try {
var result = A();
// check for error value
if (result < 0) {
throw result;
}
return B(result);
} catch(err) {
return Promise.resolve(err);
}
}
Note that both of these patterns avoid creating an extra promise if it isn't needed. They only create the extra promise when returning an error that occurred synchronously.
The Bluebird promise library has a helper function for this particular circumstance called Promise.method. The utility of Promise.method() is that it automatically wraps your function in a try/catch handler and if there are any synchronous exceptions thrown, it automatically turns them into returning a rejected promise. You could use it like this:
var someFunction = Promise.method(function() {
var result = A();
// check for error condition
if (result < 0) {
throw result;
}
return B(result);
});
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
I'm assuming that both A and B can throw errors here. Using the standard API it could look like this:
function() {
return new Promise((resolve, reject) => {
try {
resolve(A());
} catch (error) {
reject(error);
}
})
.then(B)
.catch(C);
}
This will return a promise that's either resolved with the output of B or the output of C, if that provides a fallback. You can also consider handling any errors outside of this function if that makes sense for your use case.
When using Bluebird this should also be possible:
function() {
return Promise.method(A)().then(B).catch(C)
}
I think a good way to do this would be to still use promises for the synchronous function. It keeps it consistent within a function, especially if you want something to respond to the success like a pseudo-promise. But the key is that you'd use an immediately resolved promise. Take a look at this blog post on ES6 Promises.
// an immediately resolved promise
var a = Promise.resolve(A());
assuming you've already created the promise and defined C like so:
var B = new Promise(function(resolve, reject) {
if (a) {
resolve('success'); // fulfilled successfully
}
else {
C('rejected'); // error, rejected
}
})
.then((result) => {console.log('made it!');})
.catch((result) => {C('rejected');});
var C = (err)=>{console.log('error: ' + err); return err;}
this code should do what you want:
a.then((result) => B(result));
^ this last line is the most important, since it uses the output for A to call B
I have some javasript code that takes an existing promise
(say, the promise returned by fetch()) and adds value
(say, then/catch listeners for debugging, or maybe more):
let myFetch = function(url) {
return fetch(url).then(function(value) {
console.log("fetch succeeded: value=",value);
return value;
}.catch(function(reason) {
console.log("fetch failed: reason=",reason);
throw reason;
});
};
I found myself modifying the above code so that the listeners are added only if some condition is true:
let myFetch = function(url) {
let promise = fetch(url);
if (some condition) {
promise = promise.then(function(value) {
console.log("fetch succeeded: value=",value);
return value;
}.catch(function(reason) {
console.log("fetch failed: reason=",reason);
throw reason;
});
}
return promise;
};
Now I'm wondering, does it really make sense for myFetch to return the new promise returned by "then"
(actually catch which is shorthand for another "then") as above,
or would it make more sense for it to return the original promise (with the added listeners)?
In other words, I'm thinking of leaving out the second "promise =",
so that the code will look like this instead:
let myFetch = function(url) {
let promise = fetch(url);
if (some condition) {
promise.then(function(value) {
console.log("fetch succeeded: value=",value);
return value;
}.catch(function(reason) {
console.log("fetch failed: reason=",reason);
throw reason;
});
}
return promise;
};
Is that effectively different from the previous version?
Is either version preferable, and if so, why?
If your only use case is logging something in then/catch – it shouldn't matter as long as everything goes well. Things get more messed if you get an exception. Consider these two examples:
Return original promise
function myFetch() {
let promise = new Promise(function (resolve, reject) {
resolve(100);
});
promise.then(function () { throw new Error('x'); });
return promise;
}
myFetch().then(function () {
console.log('success!');
}).catch(function (e) {
console.error('error!', e)
});
The result is success and the error thrown in the inner then might get swallowed in some promise libraries (although the most popular ones such as Bluebird handle this and you get additional error Unhandled rejection Error: x).
The error might also get swallowed when using native Promises in some environments.
Returning modified promise
function myFetch() {
let promise = new Promise(function (resolve, reject) {
resolve(100);
});
promise = promise.then(function () { throw new Error('x'); });
return promise;
}
myFetch().then(function () {
console.log('success!');
}).catch(function (e) {
console.error('error!', e)
});
Now the result is error! Error: x.
Well, if your success handler returns the value and your rejection handler throws the error - then it is basically the identity transformation for the promise.
Not only do you not need to do that promise = promise.then you don't even need to return the values:
let myFetch = function(url) {
let promise = fetch(url);
if (some condition) {
promise.then(function(value) {
console.log("fetch succeeded: value=",value);
}.catch(function(reason) {
console.log("fetch failed: reason=",reason);
});
}
return promise;
};
That said, if you're using ES6 and let, you can use arrow functions which makes this a little nicer anyway:
let myFetch = function(url) {
let promise = fetch(url);
if (some condition) {
promise.then(value => console.log("fetch succeeded: value=",value))
.catch(reason => console.log("fetch failed: reason=",reason));
}
return promise;
};
Some promise libraries like bluebird provide a tap utility for this. The only problem is that if ever fetch adds support for promise cancellation, you are breaking the chain with the if (some condition) handler if you're not chaining it.
You're promise branching. In the second case, you're effectively branching the promise chain into two promise chains, because once a caller calls myFetch:
myFetch("localhost").then(request => { /* use request */ } );
then promise will have had .then called on it twice (once inside myFetch to do the console logging, and again here).
This is fine. You can call .then on the same promise as many times as you like, and the functions will execute together in the same order whenever promise resolves.
But, importantly, each function represents a branch off of the original promise, independent of every other branch. This is why you don't need to return or rethrow anything after your console.log: Nobody's listening on that branch, specifically, the caller of myFetch is not affected.
This is a good fit for logging IMHO, but there are subtle timing and error handling differences to be aware of when doing anything more:
var log = msg => div.innerHTML += msg + "<br>";
var myFetch = url => {
var p = Promise.resolve({});
p.then(() => log("a")).then(() => log("b"));
return p;
}
myFetch().then(() => log("1")).then(() => log("2")).catch(log); // a,1,b,2
<div id="div"></div>
This emits a,1,b,2. As you can see, there are two chains going on here, advancing in parallel. It makes sense when you think about when promise is resolved, but it can be surprising.
The other subtlety is that error handling is also per branch (one branch will never fail another). In fact, the above code has a bug. Did you spot it? There should be a catch after .then(() => log("b")), or errors about anything you do in that branch end up unhandled or swallowed in some environments.
Does anybody have any thoughts about ES6 promises, I'm using them in my Node app and I love them, on the most part. But Ive found that if I get some sort of error in a resolve callback, it won't throw an error or execute the reject callback, and its leaving me with my server hanging infinitely.
For now I've resorted to doing this, and manually rejecting the promise with the caught error, but I'm not sure if this a great way to handle, and/or if I should be using promises at all.
this.dataStore.set(newID, value).then( (foo) => {
try{
this.var = foo;
res({val: foo});
}catch(e){
rej(e);
}
}, (e) => {
rej(e);
});
I think the confusion is arising from the fact that, based on your use of res, and rej here, you are likely calling this from within a promise constructor, along the lines of
function setStore(newID, value) {
return new Promise(function(res, rej) {
this.dataStore.set(newID, value).then( (foo) => {
try{
this.var = foo;
res({val: foo});
}catch(e){
rej(e);
}
}, (e) => {
rej(e);
});
});
}
By the way, the (e) => { rej(e); } part at the end could be rewritten as e => rej(e), which in turn could be rewritten as rej.
But anyway, you don't need any of that surrounding machinery to create and return your own promise, because this.dataStore.set and/or the ensuing call to then already creates a promise, which you can return as is. Instead of creating your own new promise, and then resolving your new promise with the little hash based on the result passed to then, just return the hash--that will become the value of the resulting promise. Instead of rejecting your new promise when the call to dataStore.set fails, just let the failed promise be itself.
So you shouldn't need to do anything more complicated than
function setStore(newID, value) {
return this.dataStore.set(newID, value).then(foo => {
this.var = foo;
return {val: foo};
});
}
An error occurring in the this.var = foo; return {val: foo}; part (but how could it?) will automatically throw the promise into failure state. A failure resulting from this.dataStore.set will yield a failed promise as is, and there is no need to catch it and rethrow it--the failure will progress merrily down the chain.
Use this as:
setStore('abc', 123)
.then(hash => console.log(hash.val))
.catch(e => console.log("The sky is falling", e));
As a matter of clarification, in the following:
promise.then(success, failure)
an error arising in the success callback is not handled in the failure callback. A failure in the success callback would be handled in successive stages of the chain. You could handle a failure in success (or promise itself) with
promise.then(success).catch(failure)