Reputation: 2549
Basically I have a construction like;
// Library function
function foo(){
return new Promise((resolve, reject) =>{
// Do lots of stuff, like rendering a prompt
// On user action
if(userDidSomething){
resolve(user_input);
}
if(userCanceled){
// On user cancel
reject('User canceled');
}
}).catch("Default error (usually canceling whatever it is, which means; do nothing)");
}
// Function to call library function with predefined settings for this website
function bar(){
// Have some defaults set here, like which kind of prompt it should be
return foo();
}
// Where the function will actually be used
function baz(){
bar().then("do some things");
}
I've worked my way around this issue some years ago but unfortunately forgot how I actually managed to do that.
The goal: Have one standard catch
handle things for me on the library level. If I want to overrule it, I can always do that later. So I guess it's: Break the chain.
The problem: Having the catch
before the then
, causes the then
to be triggered once I have dealt with the catch
(which is; ignoring it, in this case)
My current solution: I'm using throw
on the library-level catch
, this causes the promise to throw an uncaught error exception
.
However, this completely clutters up my console with errors which aren't really errors.
The problem is that the entire resolve
/reject
of the promise is being handled by the library. That promise gets returned around and I only call it way later.
This is a function I'm calling about 300 times throughout my project, and I don't want to be putting custom error handling on every single one of those function calls when the handling of this should be "don't do anything, really".
Upvotes: 1
Views: 77
Reputation: 18619
What you are asking for is not really possible using native Promises because that's not how they were intended to be used.
You can, though, create a custom Promise class that does this. Note that muting all rejections is a bad idea because you won't see if your code errors out. To go around that, only a special value (SpecialPromise.CANCELED
) is treated differently. The code has to track whether a .catch
is attached to it. When the promise encounters the special value and it has no catch callback at the moment, it quickly attaches a no-op catch callback to silence the error:
class SilentPromise extends Promise{
constructor(executor){
super((resolve, reject) => {
executor(
resolve,
e => {
if(e === this.constructor.CANCELED && !this._hasCatch){
this.catch(() => {})
}
reject(e)
}
)
})
this._hasCatch = false
}
then(success, error){
this._hasCatch = true
return super.then(success, error)
}
catch(error){
this._hasCatch = true
return super.catch(error)
}
catchIfNotCanceled(error){
this.catch(e => {
if(e === this.constructor.CANCELED)
throw e
return error(e)
})
}
}
SilentPromise[Symbol.species] = SilentPromise
SilentPromise.CANCELED = Symbol('CANCELED')
You can convert existing promises between SilentPromise
and Promise
using SilentPromise.resolve()
and Promise.resolve()
.
Upvotes: 1