【问题标题】:Difference between return Error and throw Error返回错误和抛出错误的区别
【发布时间】:2019-11-16 12:11:10
【问题描述】:

在一个项目中发现以下代码,看不懂:

get(key, store = null) {
    if (!key) {
      return new Error('There is no key to get!');
    }

    let dbstore = this.localforage;

    if (store !== null) {
      dbstore = store;
    }

    return dbstore
      .getItem(key)
      .then(function(value) {
        return value;
      })
      .catch(function(err) {
        return new Error('The key (' + key + ") isn't accessible: " + err);
      });
  }

为什么是return new Error('There is no key to get!'); 而不是throw new Error('There is no key to get!');

为什么不在catch 块中抛出错误?

【问题讨论】:

  • 返回错误是一件非常不寻常的事情,这不是它们的用途。
  • 这取决于您想要控制的位置。 throw 立即将控制权交还给调用者:参见 MDN:“并且控制权将传递给调用堆栈中的第一个 catch 块。如果调用者函数之间不存在 catch 块,程序将终止。”,而如果你 @ 987654327@一个新的错误,你必须在另一个位置以不同的方式处理它
  • 也许该代码的作者认为 try/catch 对代码的性能影响“太多” - 请参阅 stackoverflow.com/questions/19727905/…
  • 由于作者还添加了一个不必要的.then,所以他似乎没有那么熟练...

标签: javascript error-handling promise return


【解决方案1】:

当你设计一个函数接口并且有错误需要处理时,你可以选择如何返回错误。如果函数是同步的,您可以返回一些指示错误并且很容易与实际结果区分开来的标记值(在 Javascript 中通常为null),或者您可以throw 异常,或者您可以返回一个具有指示操作成功或失败的属性。

当您使用 Promise 接口进行异步操作时,通常会拒绝带有 Error 对象的 Promise 作为表示错误的拒绝原因。这就是 Promise 的核心设计理论。成功以可选值解决,错误以原因拒绝。

这段代码:

return dbstore
  .getItem(key)
  .then(function(value) {
    return value;
  })
  .catch(function(err) {
    return new Error('The key (' + key + ") isn't accessible: " + err);
  });

正在使用值或 Error 对象解析返回的承诺。这通常不是 promise 代码的编写方式,因为它需要调用者测试解析值的类型以确定是否存在错误,这不是使用 promise 的简单、直接的方法。所以,对于你的问题,你通常会这样做:

return dbstore.getItem(key).catch(function(err) {
    throw new Error('The key (' + key + ") isn't accessible: " + err);
});

这个函数还有其他迹象,它只是糟糕的代码。

  1. .then(function(value) {return value;}) 完全是多余和不必要的。它根本没有增加任何价值。 value 已经是 promise 的解析值。无需再次声明。

  2. 该函数有时会返回一个承诺,有时会抛出一个同步异常。
    这甚至是一个进一步的使用痛苦。如果您查看第一个 if (!key) { 语句,它会返回一个错误对象,即未提供 key 参数。这意味着要使用此函数,您必须捕获同步异常,提供 .then().catch() 处理程序并检查已解析承诺的类型以查看它是否恰好是错误对象。使用此功能是一场噩梦。这是糟糕的代码。

要按原样使用函数,调用者可能必须这样做:

let retVal = someObj.get(aKey);
if (typeof retVal === Error) {
    // got some synchronous error
} else {
    retVal.then(val => {
        if (typeof val === Error) {
            // got some asynchronous error
        } else {
            // got an actual successful value here
        }
    }).catch(err => {
        // got some asynchronous error
    })
}

函数实现大概应该是这样的:

get(key, store = null) {
    if (!key) {
        return Promise.reject(new Error('There is no key to get!'));
    }

    let dbstore = store || this.localforage;

    return dbstore.getItem(key).catch(function(err) {
        throw new Error('The key (' + key + ") isn't accessible: " + err);
    });
}

然后可以这样使用:

someObj.get(aKey).then(val => {
    // got some successful value here
}).catch(err => {
    // got some error here
});

将这里调用者的简单性与上面的混乱进行比较。

此实现具有以下一致性:

  1. 它总是返回一个承诺。如果没有提供key,它会返回一个被拒绝的promise。
  2. 所有错误都来自被拒绝的承诺
  3. promise 解析的值始终是实际成功的值
  4. 没有没有任何用处的 .then() 处理程序。

【讨论】:

  • 你能主持我的代码吗? ...这是非常有价值的
猜你喜欢
  • 1970-01-01
  • 2013-09-18
  • 1970-01-01
  • 1970-01-01
  • 2014-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
相关资源
最近更新 更多