Yes, *+1*. Filtered .catch(…) <https://web.archive.org/web/20171010234233/http://bluebirdjs.com/docs/api/catch.html#filtered-catch> is a *Bluebird* feature that I use *quite a lot*. Native support would be great. I’ve personally only ever needed to use the constructor matcher version (*i.e.*, the version which uses instanceof under the hood), but I can see why support for the other versions (object predicate and function predicate) could be useful.
On Tue, Oct 10, 2017 at 7:06 PM, Peter Jaszkowiak <[email protected]> wrote: > Excuse me if this has been discussed previously, I did try to find > existing discussions. > > Bluebird has very useful functionality in `Promise.prototype.catch`, which > allows for filtering certain error types. Here is an example: > > ```js > database.get('user:Bob') > .catch(UserNotFoundError, (err) => { > console.error('User not found: ', err); > }) > ``` > > Which is a shortcut for the following: > > ```js > database.get('user:Bob') > .catch((err) => { > if (err instanceof UserNotFoundError) { > console.error('User not found: ', err); > return; > } > > throw err; > }) > ``` > > I think this would be a huge improvement to error handling in asynchronous > situations, especially since many people dislike using `try { ... } catch > (e) { ... }` syntax (which would also benefit from some sort of error > filtering). > > ### Options > > I think that passing in the matching argument as the second argument is > preferable to passing it as the first argument, but in the spririt of > compatibility, supporting it in the Bluebird fashion is best. > Alternatively, a new prototype method (like `catchFilter` or `error`) could > be used to instead support the same functionality. > > Terminology: > - Callback > The function passed as the next operation in the chain, to be called if > a rejection occurs > - Matcher > The argument passed to select a certain type of error to be caught, and > then execute the provided callback > > #### Use `instanceof` > The class or constructor would be passed as the matcher > > This on its own is It would not support instances from other contexts, > nor would it support custom errors created without subclassing (like > manually setting error.name). > > Example > ```js > const err = new CustomError(); > Promise.reject(err) > .catch(CustomError, (customError) => { > // handle CustomError s > }) > .catch((otherError) => { > // handle other errors > }); > ``` > > #### Use pattern matching > An object would be passed as the matcher, and it's own enumerable > properties would be compared with properties of the error instance. If all > properties on the given matcher are strictly equal to the same properties > on the error instance, it's a match. > > Example: > ```js > const err = new Error(); > err.name = 'CustomError'; > Promise.reject(err) > .catch({ name: 'CustomError' }, (customError) => { > // handle CustomError s > }) > .catch((otherError) => { > // handle other errors > }); > ``` > > This would allow for matching any error type, and could support a subset > of the `instanceof` check by doing something like `{ constructor: > CustomError }`. > > #### Use a matcher function > A function would be passed as the matcher, receiving the err as its > argument. It would then be able to do any operation on the error instance > to check if it is the correct error type. > > Example: > ```js > const err = new Error(); > err.name = 'CustomError'; > Promise.reject(err) > .catch(err => (err.name === 'CustomError'), (customError) => { > // handle CustomError s > }) > .catch((otherError) => { > // handle other errors > }); > ``` > > However, this is almost no different from just including the tests in the > catch body itself. It's verbose enough that the benefit of supporting this > is not nearly as significant than the other options. > > #### Support `instanceof` and pattern matching > In my opinion, this is the best of both worlds. You get to support the > basic `instanceof` case with inheritance, etc, while also supporting > matching more custom errors made in a less standard manner. > > The method would check if the matcher is a function, and if so, it would > use `instanceof`. Otherwise, it would treat the argument as an object and > compare the properties. > > > ### Example Naive Polyfill > > ```js > const origCatch = Promise.prototype.catch; > Promise.prototype.catch = { catch (ErrorType, callback) { > if (typeof callback !== 'function' && typeof ErrorType === 'function') { > callback = ErrorType; > ErrorType = null; > } > > if (!ErrorType || !(typeof ErrorType === 'object' || typeof ErrorType > === 'function')) { > return origCatch.call(this, callback); > } > > // if the ErrorType is a function, use instanceof > if (typeof ErrorType === 'function') { > return origCatch.call(this, (err) => { > if (err instanceof ErrorType) { > return callback(err); > } > > throw err; > }); > } > > // otherwise use pattern matching > return origCatch.call(this, (err) => { > const matches = Object.entries(ErrorType) > .every(([key, value]) => (err[key] === value)); > if (matches) { > return callback(err); > } > > throw err; > }); > } }.catch; > ``` > > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss > > -- - Jonathan — Life is a game and we’re all just high density pixels.
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

