I want to remove indentations in a javascript funtion that inside has a variable that recive the value of a promise. Inside of it has a try-catch with some code and inside the try section has a fetch with his own then and catch.
My question is, how can I simplify the code, even creating new functions if needed, to reduce the amount of indentations.
Thanks for advance.
Here an example code:
function getData(url) {
const myVariable = new Promise((resolve, reject) => {
try {
fetch(url)
.then((resp) => resp.json())
.then(json) => {
//some code here
});
// more code here
resolve();
})
.catch(() => { // this catch is of the fetch
// more code here
resolve();
});
} catch (error) {
// more code here
reject();
}
});
}
Y tried to transform the fetch using the ES6 async-await but I can not use an async funtion inside a promise
You don't need a new Promise. Once you have a promise -- like returned by fetch() -- you don't need another promise to tell you when the first one resolves. The same is true when you have a promise coming from then() calls: you don't need an extra promise for them. It is an antipattern to use the promise constructor callback just to create another promise (using some API).
Your example code has syntax issues (there are more closing braces than opening), so the .catch() method is not called on a promise. Your comment suggests you want to call it on the promise returned by fetch, but then it should be chained before the first then call. Each then() returns a new promise, and maybe you wanted to chain .catch() on the last .then(). In that case it will catch rejections of any of the previously chained promises, which means the outer try/catch block is not going to ever execute the catch block -- there is nothing remaining that can cause a run time error.
Another issue with the code (once its syntax errors are fixed) is that although myVariable will be assigned a promise:
That promise will resolve to undefined
The getData function will return a promise that will resolve to undefined
That is not very useful. You should resolve that promise with the data you got from the json() promise.
You can use async await like so:
async function getData(url) {
try {
const resp = await fetch(url);
} catch(err) {
console.log("fetch failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
try {
const data = await resp.json();
} catch(err) {
console.log("json() failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
return data;
}
As in this example the error handling is nothing more than just reporting on errors and then bubble the error upwards, it would make sense that the caller would take the responsibility to report on errors:
function getData(url) {
fetch(url).then(resp => resp.json());
}
I'm nesting Promises and I have to know whether the nested Promise is a rejected Promise or a fulfilled Promise to know whether to trigger the outer Promise chain's catch. To differentiate if the nested Promise is rejected or fulfilled, I use a throw in my nested Promise's catch to indicate rejection; while fulfillment is always indicated when there's no throw in my nested Promise's catch. Please take a look at the example below:
let test = new Promise((resolve, reject) => {
resolve(42);
}).then((e) => {
console.log(e);
return new Promise((resolve, reject) => { //Error happens inside this nested Promise
resolve(32);
}).then((e) => {
console.log(e);
//Run other processes that may lead to an error
}).catch((e) => { //I added this catch block for error detection, whatever error it might be
console.log(e);
throw(e); //I'm throwing (e) from the inner Promise's catch so that the returned Promise in the outer then is a rejected Promise, which will be "caught" by the catch block of the outer Promise
});
}).catch((e) => {
console.log(e); //I handle error that happen may either in the inner Promise or the outer Promise here
});
The above shows what I meant by throw-ing inside the catch block of my nested Promise. Is the above the standard way to indicate that a nested Promise failed, or is there an alternative cleaner method to achieve what I want? As you can see, I'm practically throw-ing twice inside my nested Promise to indicate rejection. Is there a way where I can throw once and indicate Promise rejection?
EDIT
The reasons I'm using a catch block in my inner Promise and my outer Promise: I want to detect error inside my inner Promise, and said detection is done using my inner catch block; I want to handle the error that may happen in the inner Promise or in the outer Promise with the same handler, and that is done using my outer catch block. Because catch-ing inside my inner Promise returns a Promise that is considered fulfilled to my outer Promise's then block, I decided to use throw inside my inner catch block to indicate that it actually isn't fulfilled if it reached the inner catch block. I've also edited my code to indicate that the error happening inside my inner Promise is not manually triggered by me throw-ing in the code.
I think the clean way to do this would be using async/await. But before going there, is your question how to not run the outer promise when the inner promise fails?
The example below:
When the inner promise rejects, the chain stops.
When the outer promise rejects, the inner is already fulfilled.
const fun42 = () => {
return new Promise((resolve, reject) => {
setTimeout(() =>{
resolve(42)
reject('something at fun 42 went wrong')
}, 500)
})
}
const fun32 = () => {
return new Promise((resolve, reject) => {
setTimeout(() =>{
//resolve(32)
reject('something at fun 32 went wrong')
}, 500)
})
}
fun32().then(x => {
console.log(x)
return fun42()
}).then( y => {
console.log(y)
}).catch (e => {
console.log(e)
})
Well, it's a question of design. Error handling should happen in one place on each level (like you did in your example). The nested catch function handles the error the decide whether it should propagate it or quietly finish it (like your wrote).
In that specific example I would use the reject function of the wrapping Promise to reject it, other than throwing an error.
I have one array of promises that each one execute a code that can have a javascript error and break the script. I need to check for each promise and catch any error. The problem is that the promise has timeout functions inside. Is there anyway to solve this?
Example code:
function apiRequest(url,customError) {
return new Promise(function (resolve, reject) {
if(customError) {
setTimeout(() => {
//Force error
var ar = url.asdasd.eadasd;
ar = ar.split('123')
},3000)
}
if (url) {
return resolve(url);
} else {
return reject('apiRequest failed!');
}
})
.catch(function(err){
return 'error on javascript code';
});
}
var p1 = apiRequest('urlOne',true);
var p2 = apiRequest(false,false);
var p3 = apiRequest('urlThree');
Promise.all([p1, p2, p3])
.then(function(res){
console.log('Promise.all', res);
}, error => {
console.log('Error on reject')
})
.catch(function(err){
console.error('err', err);
});
Result:
Promise.all [ 'urlOne', 'error on javascript code', 'urlThree' ]
var ar = url.asdasd.eadasd;
TypeError: Cannot read property 'eadasd' of undefined
If there is an error inside each promise, my code can catch it but if there is a timeout and the error happends after the promise finish I cant catch it and my code breaks, is there anyway to catch this error?
Is there any way to check error in each Promise in promise.all when there is a promise error?
By design, Promise.all() resolves when ALL promises you passed it have resolved or it rejects when any single promise in it rejects. It does not, by design, wait for all promises to resolve or reject and then give you all the results whether they resolved or rejected.
Functionality like that is typically named something like Promise.settle() and you can fairly easily build that type of functionality by just adding a .catch() handler to each promise you pass Promise.all() so that instead of rejecting, it resolves, but with a value that you can later tell that it actually rejected.
You can see several various implementations of .settle() type functionality in this answer:
ES6 Promise.all() error handle - Is .settle() needed?
If there is an error inside each promise, my code can catch it but if there is a timeout and the error happends after the promise finish I cant catch it and my code breaks, is there anyway to catch this error?
The way you have structured your setTimeout(), it is not connected at all to the promise that it is inside of. If you want them connected, then you have to wait to resolve until after the timeout is done and then, and only then, can you know if you should resolve or reject.
Since the code you show inside your setTimeout() looks like pseudo-code (that doesn't actually do anything yet), it's hard for us to see exactly what the point of the setTimeout() is to know exactly what you are trying to achieve and thus what a good suggestion would be.
This answer about using setTimeout() as part of a promise chain might be relevant:
using setTimeout on promise chain.
In that case, the timer is inserted into the promise chain so that things are sequenced before it and after it. As you show it now, it's a completely separate parallel path of execution that has no connection at all to your promise chain.
If all you're trying to do with the setTimeout() is to invoke a timeout if your api request does not return before the timer fires, then you can likely implement that by just calling reject() inside the setTimeout(). If the api request has already completed and already called resolve(), then calling reject() will do nothing at that point. If the api request has not yet finished, then calling reject() will reject the host promise.
What exactly is the difference? In the two scenarios below, what type of difference does myPromise have?
Here is the example:
Case 1. Returning a promise
function test() {
return somePromise.then(() => {
return anotherPromise.then(res => {
console.log('Result:', res);
});
}).catch(err => {
console.error(err);
});
}
const myPromise = test();
Case 2. Not returning a promise
function test() {
return somePromise.then(() => {
anotherPromise.then(res => {
console.log('Result:', res);
});
}).catch(err => {
console.error(err);
});
}
const myPromise = test();
The first case is "promise chaining" and it a very common and useful tool. By returning a promise from a .then() handler, you are telling the parent promise that you want it to wait until the returned promise is done before resolving itself. This allows you to create a sequence of events and know when the entire sequence is done by monitoring the top level promise. Anyone watching the parent promise will only see a resolve or reject when the "chained" promise is also resolved or rejected. Errors from the chained promise will propagate upwards.
Also, the resolved value of the parent promise will become the resolved value of the chained promise.
The second case is just starting a new promise chain that is not connected to the original one in any way. It won't propagate errors and the parent promise won't wait for it. It's kind of like a "fire and forget" operation where you're running it separately, but not connecting it at all to the parent operation.
This is usually a "bug" (though there are occasionally situations where you want to start a new async operation and are not reporting its success or failure back to anyone). In the code you show, if anotherPromise rejected, you'd get a warning about an unhandled rejection because it is not chained and will not propagate up to your .catch().
Well for one, the second one's catch block would not be hit if there was a problem with the nested promise.
First case will wait until the anotherPromise will be resolved or rejected, then pass the execution to the next then of somePromise with the resolved or rejected value of the anotherPromise. So the chain is made by the values of both anotherPromise and somePromise.
Second will just run the inner promise, forget about it and return the execution to the next then of somePromise with the resolved or rejected value of the somePromise. So the chain is made by the values of only somePromise.
In the first case, myPromise will not resolve until both somePromise and anotherPromise have resolved.
In the second case, myPromise will resolve as soon as somePromise resolves. Additionally, the catch handler will not catch any error from anotherPromise if it rejects.
The latter is generally an antipractice because it is an example of "fire and forget" code.
Bear in mind that you are also building up a "pyramid of doom" there. A preferable approach to both of those examples would be:
function test() {
return somePromise
.then(() => anotherPromise)
.then(res => {
console.log('Result:', res);
})
.catch(err => {
console.error(err);
});
}
const myPromise = test();
I am have a problem understanding why rejections are not passed on through a promise chain and I am hoping someone will be able to help me understand why. To me, attaching functionality to a chain of promises implies an intent that I am depending on an original promise to be fulfilled. It's hard to explain, so let me show a code example of my problem first. (Note: this example is using Node and the deferred node module. I tested this with Dojo 1.8.3 and had the same results)
var d = require("deferred");
var d1 = d();
var promise1 = d1.promise.then(
function(wins) { console.log('promise1 resolved'); return wins;},
function(err) { console.log('promise1 rejected'); return err;});
var promise2 = promise1.then(
function(wins) { console.log('promise2 resolved'); return wins;},
function(err) { console.log('promise2 rejected'); return err;});
var promise3 = promise2.then(
function(wins) { console.log('promise3 resolved'); return wins;},
function(err) { console.log('promise3 rejected'); return err;});
d1.reject(new Error());
The results of running this operation is this output:
promise1 rejected
promise2 resolved
promise3 resolved
Okay, to me, this result doesn't make sense. By attaching to this promise chain, each then is implying the intent that it will be dependant upon the successful resolution of d1 and a result being passed down the chain. If the promise in promise1 doesn't receive the wins value, but instead gets an err value in its error handler, how is it possible for the next promise in the chain to have its success function called? There is no way it can pass on a meaningful value to the next promise because it didn't get a value itself.
A different way I can describe what I'm thinking is: There are three people, John, Ginger, and Bob. John owns a widget shop. Ginger comes into his shop and requests a bag of widgets of assorted colours. He doesn't have them in stock, so he sends in a request to his distributor to get them shipped to him. In the mean time, he gives Ginger a rain check stating he owes her the bag of widgets. Bob finds out Ginger is getting the widgets and requests that he get the blue widget when she's done with them. She agrees and gives him a note stating she will. Now, John's distributor can't find any widgets in their supply and the manufacturer doesn't make them any more, so they inform John, who in turn informs Ginger she can't get the widgets. How is Bob able to get a blue widget from Ginger when didn't get any herself?
A third more realistic perspective I have on this issue is this. Say I have two values I want updated to a database. One is dependant on the id of the other, but I can't get the id until I have already inserted it into a database and obtained the result. On top of that, the first insert is dependant on a query from the database. The database calls return promises that I use to chain the two calls into a sequence.
var promise = db.query({parent_id: value});
promise.then(function(query_result) {
var first_value = {
parent_id: query_result[0].parent_id
}
var promise = db.put(first_value);
promise.then(function(first_value_result) {
var second_value = {
reference_to_first_value_id: first_value_result.id
}
var promise = db.put(second_value);
promise.then(function(second_value_result) {
values_successfully_entered();
}, function(err) { return err });
}, function(err) { return err });
}, function(err) { return err });
Now, in this situation, if the db.query failed, it would call the err function of the first then. But then it would call the success function of the next promise. While that promise is expecting the results of the first value, it would instead get the error message from its error handler function.
So, my question is, why would I have an error handing function if I have to test for errors in my success function?
Sorry for the length of this. I just didn't know how to explain it another way.
UPDATE and correction
(Note: I removed a response I had once made to some comments. So if anyone commented on my response, their comments might seem out of context now that I removed it. Sorry for this, I am trying to keep this as short as possible.)
Thank you everybody who replied. I would like to first apologize to everybody for writing out my question so poorly, especially my pseudo code. I was a little too aggressive in trying to keep it short.
Thanks to Bergi's response, I think I found the error in my logic. I think I might have overlooked another issue that was causing the problem I was having. This is possibly causing the promise chain work differently than I thought it should. I am still testing different elements of my code, so I can't even form a proper question to see what I'm doing wrong yet. I did want to update you all though and thank you for your help.
To me, this result doesn't make sense. By attaching to this promise chain, each then is implying the intent that it will be dependant upon the successful resolution of d1 and a result being passed down the chain
No. What you are describing is not a chain, but just attaching all the callbacks to d1. Yet, if you want to chain something with then, the result for promise2 is dependent on the resolution of promise1 and how the then callbacks handled it.
The docs state:
Returns a new promise for the result of the callback(s).
The .then method is usually looked upon in terms of the Promises/A specification (or the even stricter Promsises/A+ one). That means the callbacks shell return promises which will be assimilated to become the resolution of promise2, and if there is no success/error handler the respective result will in case be passed directly to promise2 - so you can simply omit the handler to propagate the error.
Yet, if the error is handled, the resulting promise2 is seen as fixed and will be fulfilled with that value. If you don't want that, you would have to re-throw the error, just like in a try-catch clause. Alternatively you can return a (to-be-)rejected promise from the handler. Not sure what Dojo way to reject is, but:
var d1 = d();
var promise1 = d1.promise.then(
function(wins) { console.log('promise1 resolved'); return wins;},
function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
function(wins) { console.log('promise2 resolved'); return wins;},
function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
function(wins) { console.log('promise3 resolved'); return wins;},
function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());
How is Bob able to get a blue widget from Ginger when didn't get any herself?
He should not be able. If there are no error handlers, he will just perceive the message (((from the distributor) from John) from Ginger) that there are no widgets left. Yet, if Ginger sets up an error handler for that case, she still might fulfill her promise to give Bob a widget by giving him a green one from her own shack if there are no blue ones left at John or his distributor.
To translate your error callbacks into the metapher, return err from the handler would just be like saying "if there are no widgets left, just give him the note that there are no ones left - it's as good as the desired widget".
In the database situation, if the db.query failed, it would call the err function of the first then
…which would mean that the error is handled there. If you don't do that, just omit the error callback. Btw, your success callbacks don't return the promises they are creating, so they seem to be quite useless. Correct would be:
var promise = db.query({parent_id: value});
promise.then(function(query_result) {
var first_value = {
parent_id: query_result[0].parent_id
}
var promise = db.put(first_value);
return promise.then(function(first_value_result) {
var second_value = {
reference_to_first_value_id: first_value_result.id
}
var promise = db.put(second_value);
return promise.then(function(second_value_result) {
return values_successfully_entered();
});
});
});
or, since you don't need the closures to access result values from previous callbacks, even:
db.query({parent_id: value}).then(function(query_result) {
return db.put({
parent_id: query_result[0].parent_id
});
}).then(function(first_value_result) {
return db.put({
reference_to_first_value_id: first_value_result.id
});
}.then(values_successfully_entered);
#Jordan firstly as commenters noted, when using deferred lib, your first example definitely produces result you expect:
promise1 rejected
promise2 rejected
promise3 rejected
Secondly, even if it would produce output you suggest, it wouldn't affect execution flow of your second snippet, which is a bit different, more like:
promise.then(function(first_value) {
console.log('promise1 resolved');
var promise = db.put(first_value);
promise.then(function (second_value) {
console.log('promise2 resolved');
var promise = db.put(second_value);
promise.then(
function (wins) { console.log('promise3 resolved'); },
function (err) { console.log('promise3 rejected'); return err; });
}, function (err) { console.log('promise2 rejected'); return err;});
}, function (err) { console.log('promise1 rejected'); return err});
and that, in case of first promise being rejected will just output:
promise1 rejected
However (getting to the most interesting part) even though deferred library definitely returns 3 x rejected, most of other promise libraries will return 1 x rejected, 2 x resolved (that leads to assumption you got those results by using some other promise library instead).
What's additionally confusing, those other libraries are more correct with their behavior. Let me explain.
In a sync world counterpart of "promise rejection" is throw. So semantically, async deferred.reject(new Error()) in sync equals to throw new Error().
In your example you're not throwing errors in your sync callbacks, you just returning them, therefore you switch to success flow, with an error being a success value. To make sure rejection is passed further, you need to re-throw your errors:
function (err) { console.log('promise1 rejected'); throw err; });
So now question is, why do deferred library took returned error as rejection?
Reason for that, is that rejection in deferred works a bit different. In deferred lib the rule is: promise is rejected when it's resolved with an instance of error, so even if you do deferred.resolve(new Error()) it will act as deferred.reject(new Error()), and if you try to do deferred.reject(notAnError) it will throw an exception saying, that promise can be rejected only with instance of error. That makes clear why error returned from then callback rejects the promise.
There is some valid reasoning behind deferred logic, but still it's not on par with how throw works in JavaScript, and due to that this behavior is scheduled for change with version v0.7 of deferred.
Short summary:
To avoid confusion and unexpected results just follow the good practice rules:
Always reject your promises with an error instances (follow rules of sync world, where throwing value that's not an error is considered a bad practice).
Reject from sync callbacks by throwing errors (returning them doesn't guarantee rejection).
Obeying to above, you'll get both consistent and expected results in both deferred and other popular promise libraries.
Use can wrap the errors at each level of the Promise. I chained the errors in TraceError:
class TraceError extends Error {
constructor(message, ...causes) {
super(message);
const stack = Object.getOwnPropertyDescriptor(this, 'stack');
Object.defineProperty(this, 'stack', {
get: () => {
const stacktrace = stack.get.call(this);
let causeStacktrace = '';
for (const cause of causes) {
if (cause.sourceStack) { // trigger lookup
causeStacktrace += `\n${cause.sourceStack}`;
} else if (cause instanceof Error) {
causeStacktrace += `\n${cause.stack}`;
} else {
try {
const json = JSON.stringify(cause, null, 2);
causeStacktrace += `\n${json.split('\n').join('\n ')}`;
} catch (e) {
causeStacktrace += `\n${cause}`;
// ignore
}
}
}
causeStacktrace = causeStacktrace.split('\n').join('\n ');
return stacktrace + causeStacktrace;
}
});
// access first error
Object.defineProperty(this, 'cause', {value: () => causes[0], enumerable: false, writable: false});
// untested; access cause stack with error.causes()
Object.defineProperty(this, 'causes', {value: () => causes, enumerable: false, writable: false});
}
}
Usage
throw new TraceError('Could not set status', srcError, ...otherErrors);
Output
Functions
TraceError#cause - first error
TraceError#causes - list of chained errors
a simple explanation from here:
In a regular try..catch we can analyze the error and maybe rethrow it if it can’t be handled. The same thing is possible for promises.
If we throw inside .catch, then the control goes to the next closest error handler. But if we handle the error and finish normally, then it continues to the next closest successful .then handler.
In the example below the .catch successfully handles the error:
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) {
alert("The error is handled, continue normally");
}).then(() => alert("Next successful handler runs"));
Here the catch block finishes normally. So the next successful then handler is called.
note that we may have as many .then handlers as we want, and then use a single .catch at the end to handle errors in all of them.
If you have mid catch blocks and you want to break the next chain functions for errors, you shall re-throw the errors inside the catch blocks to signal this error is not handled completely.
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) { // (*) first catch
if (error instanceof URIError) { //just as example
// handle it...
} else {
alert("Can't handle such error");
throw error; // throwing this jumps to the next catch
}
}).then(function() {
// our error is other than URIError, so:
// the code doesn't reach here (jump to next catch)
}).catch(error => { // (**) second catch
alert(`The unknown error has occurred: ${error}`);
// don't return anything => execution goes the normal way
});
In the above example we see the first catch (*) will catch the error but can’t handle it (e.g. it only knows how to handle URIError), so it throws it again. The execution jumps from the first catch (*) to the next one (**) down the chain.