异步承诺失败时首选throw或reject

Prefer throw or reject when failing promise asynchronously

本文关键字:throw reject 承诺 失败 异步      更新时间:2023-09-26

我有一个Bluebird承诺,它包装了一个AJAX请求,并且需要在请求失败时拒绝该承诺。我想提供请求失败的原因,主要从状态码中提取,到可能附加的任何捕获块。为了实现这一点,我有UnauthorizedErrorNotFoundError以及类似的类,它们都扩展了Error以与蓝鸟的模式匹配的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();
    });
  }
}

Promise构造函数内部

promise构造函数是抛出安全的,但从本质上讲,你通常不会在内部处理抛出安全的事情——因此,例如下面的代码是不安全的:

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

promise构造函数通常只用于将回调api转换为承诺,由于回调不像承诺那样具有抛出安全,因此当它们异步出错(而不是抛出)时,您必须拒绝。

then处理程序内部

两者功能相同。当您从then处理程序中执行throw时,您将返回一个被拒绝的承诺。我更喜欢throw,因为它比return更明确地表明发生了错误,但这并不重要。

对于除Angular 1之外的任何承诺实现都是如此。x的$q区分两者-但它是奇怪的球(当你throw在那里它记录,即使你处理错误)。

在你的代码

在你的代码中,拒绝和处理承诺的方式有几个bug。承诺是非常健壮的,因为它们为你优雅地处理错误——在这方面,当你将回调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
        });
    }
}