异步失败时更喜欢抛出或拒绝

ssu*_*ube 4 javascript error-handling promise ecmascript-6 bluebird

我有一个包含AJAX请求的Bluebird承诺,需要在请求失败时拒绝承诺.我想提供为什么请求失败的原因,主要是从状态代码中提取到可能附加的任何catch块.为了实现这一点,我有UnauthorizedErrorNotFoundError类似的类,都扩展Error到与Bluebird的模式匹配catch.

我不确定的部分是我应该throw还是调用拒绝处理程序.我的代码看起来像:

class Request {
  // other methods

  send(method, url, args, body) {
    return new Promise((res, rej) => {
      let xhr = new XMLHttpRequest();
      xhr.open(method, url);

      xhr.onload = () => {
        res(JSON.parse(xhr.responseText));
      };

      xhr.onerror = () => {
        let status = xhr.status;
        switch (status) {
          case 401:
            // Should I use throw:
            throw new UnauthorizedError(url);
            // or
            rej(new UnauthorizedError(url));
        }
      };

      xhr.send();
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*aum 6

Promise构造函数内部

promise构造函数是安全的,但本质上你通常不处理内部抛出安全的东西 - 所以例如以下是不安全的:

new Promise(function(resolve, reject){
     setTimeout(function(){
         // NEVER throw here, it'll throw globally and not reject the promise
     }, 100);
});
Run Code Online (Sandbox Code Playgroud)

promise构造函数通常仅用于将回调API转换为promises,并且因为回调不像是在异步错误(而不是抛出)时必须拒绝的promises.

then处理程序内部

这两者在功能上是相同的.当你throw从一个then处理程序中返回被拒绝的承诺时.我更喜欢抛出,因为它更明确地表示错误发生了return但不重要.

对于除Angular 1.x之外的任何承诺实现都是如此,$q它区分了两者 - 但它是奇数球(throw即使你处理错误也会记录它).

在你的代码中

在您的代码中,您拒绝和处理承诺的方式存在一些错误.Promise非常强大,因为它们可以优雅地为您处理错误 - 在将回调API转换为承诺时,您必须非常小心:

class Request {
    // other methods

    send(method, url, args, body) {
        return new Promise((res, rej) => {  // it's good that new Promise is the first
            let xhr = new XMLHttpRequest(); // line since it's throw-safe. This is why it
            xhr.open(method, url);          // was chosen for the API and not deferreds

            xhr.onload = () => {
                // This _needs_ a try/catch, it will fail if responseText
                // is invalid JSON and will throw to the global scope instead of rejecting
                res(JSON.parse(xhr.responseText));
            };

            xhr.onerror = () => {
                let status = xhr.status;
                switch (status) {
                case 401:
                    // this _must_ be a reject, it should also generally be surrounded
                    // with a try/catch
                    rej(new UnauthorizedError(url));
                }
            };

            xhr.send(); // it's important that this is in the promise constructor
        });
    }
}
Run Code Online (Sandbox Code Playgroud)