<div dir="ltr"><span style="color:rgb(0,0,0);font-family:Times;font-size:medium">Yes, </span><strong style="color:rgb(0,0,0);font-family:Times;font-size:medium">+1</strong><span style="color:rgb(0,0,0);font-family:Times;font-size:medium">. </span><a href="https://web.archive.org/web/20171010234233/http://bluebirdjs.com/docs/api/catch.html#filtered-catch" title=".catch | bluebird" style="font-family:Times;font-size:medium">Filtered <code>.catch(…)</code></a><span style="color:rgb(0,0,0);font-family:Times;font-size:medium"> is a </span><strong style="color:rgb(0,0,0);font-family:Times;font-size:medium">Bluebird</strong><span style="color:rgb(0,0,0);font-family:Times;font-size:medium"> feature that I use </span><em style="color:rgb(0,0,0);font-family:Times;font-size:medium">quite a lot</em><span style="color:rgb(0,0,0);font-family:Times;font-size:medium">. Native support would be great. I’ve personally only ever needed to use the constructor matcher version (</span><em style="color:rgb(0,0,0);font-family:Times;font-size:medium">i.e.</em><span style="color:rgb(0,0,0);font-family:Times;font-size:medium">, the version which uses </span><code style="color:rgb(0,0,0)">instanceof</code><span style="color:rgb(0,0,0);font-family:Times;font-size:medium"> under the hood), but I can see why support for the other versions (object predicate and function predicate) could be useful.</span><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 10, 2017 at 7:06 PM, Peter Jaszkowiak <span dir="ltr"><<a href="mailto:p.jaszkow@gmail.com" target="_blank">p.jaszkow@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="auto"><div dir="ltr"><div dir="ltr"><div dir="ltr">Excuse me if this has been discussed previously, I did try to find existing discussions.</div><div dir="ltr"><br></div><div dir="ltr">Bluebird has very useful functionality in `Promise.prototype.catch`, which allows for filtering certain error types. Here is an example:</div><div dir="ltr"><br></div><div dir="ltr">```js</div><div dir="ltr">database.get('user:Bob')</div><div dir="ltr">  .catch(UserNotFoundError, (err) => {</div><div dir="ltr">    console.error('User not found: ', err);</div><div dir="ltr">  })</div><div dir="ltr">```</div><div dir="ltr"><br></div><div dir="ltr">Which is a shortcut for the following:</div><div dir="ltr"><br></div><div dir="ltr">```js</div><div dir="ltr">database.get('user:Bob')</div><div dir="ltr">  .catch((err) => {</div><div dir="ltr">    if (err instanceof UserNotFoundError) {</div><div dir="ltr">      console.error('User not found: ', err);</div><div dir="ltr">      return;</div><div dir="ltr">    }</div><div dir="ltr"><br></div><div dir="ltr">    throw err;</div><div dir="ltr">  })</div><div dir="ltr">```</div><div dir="ltr"><br></div><div dir="ltr">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).</div><div dir="ltr"><br></div><div dir="ltr">### Options</div><div dir="ltr"><br></div><div dir="ltr">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.</div><div dir="ltr"><br></div><div dir="ltr">Terminology:</div><div dir="ltr">- Callback  </div><div dir="ltr">  The function passed as the next operation in the chain, to be called if a rejection occurs</div><div dir="ltr">- Matcher</div><div dir="ltr">  The argument passed to select a certain type of error to be caught, and then execute the provided callback</div><div dir="ltr"><br></div><div dir="ltr">#### Use `instanceof`</div><div dir="ltr">The class or constructor would be passed as the matcher</div><div dir="ltr"><br></div><div dir="ltr">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 <a href="http://error.name" target="_blank">error.name</a>).</div><div dir="ltr"><br></div><div dir="ltr">Example</div><div dir="ltr">```js</div><div dir="ltr">const err = new CustomError();</div><div dir="ltr">Promise.reject(err)</div><div dir="ltr">  .catch(CustomError, (customError) => {</div><div dir="ltr">    // handle CustomError s</div><div dir="ltr">  })</div><div dir="ltr">  .catch((otherError) => {</div><div dir="ltr">    // handle other errors</div><div dir="ltr">  });</div><div dir="ltr">```</div><div dir="ltr"><br></div><div dir="ltr">#### Use pattern matching</div><div dir="ltr">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.</div><div dir="ltr"><br></div><div dir="ltr">Example:</div><div dir="ltr">```js</div><div dir="ltr">const err = new Error();</div><div dir="ltr"><a href="http://err.name" target="_blank">err.name</a> = 'CustomError';</div><div dir="ltr">Promise.reject(err)</div><div dir="ltr">  .catch({ name: 'CustomError' }, (customError) => {</div><div dir="ltr">    // handle CustomError s</div><div dir="ltr">  })</div><div dir="ltr">  .catch((otherError) => {</div><div dir="ltr">    // handle other errors</div><div dir="ltr">  });</div><div dir="ltr">```</div><div dir="ltr"><br></div><div dir="ltr">This would allow for matching any error type, and could support a subset of the `instanceof` check by doing something like `{ constructor: CustomError }`.</div><div dir="ltr"><br></div><div dir="ltr">#### Use a matcher function</div><div dir="ltr">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. </div><div dir="ltr"><br></div><div dir="ltr">Example:</div><div dir="ltr">```js</div><div dir="ltr">const err = new Error();</div><div dir="ltr"><a href="http://err.name" target="_blank">err.name</a> = 'CustomError';</div><div dir="ltr">Promise.reject(err)</div><div dir="ltr">  .catch(err => (<a href="http://err.name" target="_blank">err.name</a> === 'CustomError'), (customError) => {</div><div dir="ltr">    // handle CustomError s</div><div dir="ltr">  })</div><div dir="ltr">  .catch((otherError) => {</div><div dir="ltr">    // handle other errors</div><div dir="ltr">  });</div><div dir="ltr">```</div><div dir="ltr"><br></div><div dir="ltr">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.</div><div dir="ltr"><br></div><div dir="ltr">#### Support `instanceof` and pattern matching</div><div dir="ltr">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.</div><div dir="ltr"><br></div><div dir="ltr">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.</div><div dir="ltr"><br></div><div dir="ltr"><br></div><div dir="ltr">### Example Naive Polyfill</div><div dir="ltr"><br></div><div dir="ltr">```js</div><div dir="ltr">const origCatch = Promise.prototype.catch;</div><div dir="ltr">Promise.prototype.catch = { catch (ErrorType, callback) {</div><div dir="ltr">  if (typeof callback !== 'function' && typeof ErrorType === 'function') {</div><div dir="ltr">    callback = ErrorType;</div><div dir="ltr">    ErrorType = null;</div><div dir="ltr">  }</div><div dir="ltr"><br></div><div dir="ltr">  if (!ErrorType || !(typeof ErrorType === 'object' || typeof ErrorType === 'function')) {</div><div dir="ltr">    return origCatch.call(this, callback);</div><div dir="ltr">  }</div><div dir="ltr"><br></div><div dir="ltr">  // if the ErrorType is a function, use instanceof</div><div dir="ltr">  if (typeof ErrorType === 'function') {</div><div dir="ltr">    return origCatch.call(this, (err) => {</div><div dir="ltr">      if (err instanceof ErrorType) {</div><div dir="ltr">        return callback(err);</div><div dir="ltr">      }</div><div dir="ltr"><br></div><div dir="ltr">      throw err;</div><div dir="ltr">    });</div><div dir="ltr">  }</div><div dir="ltr"><br></div><div dir="ltr">  // otherwise use pattern matching</div><div dir="ltr">  return origCatch.call(this, (err) => {</div><div dir="ltr">    const matches = Object.entries(ErrorType)</div><div dir="ltr">      .every(([key, value]) => (err[key] === value));</div><div dir="ltr">    if (matches) {</div><div dir="ltr">      return callback(err);</div><div dir="ltr">    }</div><div dir="ltr"><br></div><div dir="ltr">    throw err;</div><div dir="ltr">  });</div><div dir="ltr">} }.catch;</div><div dir="ltr">```</div><div><br></div></div></div></div>
</div>
<br>______________________________<wbr>_________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" rel="noreferrer" target="_blank">https://mail.mozilla.org/<wbr>listinfo/es-discuss</a><br>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr">- Jonathan</div><div dir="ltr"><br></div><div dir="ltr">—</div><div dir="ltr"><br></div><div dir="ltr">Life is a game and we’re all just high density pixels.</div></div></div></div></div>
</div>