JavaScript承诺 - 拒绝与抛出

本文探讨了JavaScript中Promise.reject与throw在处理异步错误时的差异。Promise.reject允许在Promise被拒绝后继续异步执行,而throw则会立即终止当前执行流程。在Promise回调中,throw会自动转化为被拒绝的Promise,但在其他异步环境中,必须使用Promise.reject。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自:JavaScript Promises - reject vs. throw

I have read several articles on this subject, but it is still not clear to me if there is a difference between Promise.reject vs. throwing an error. 我已经阅读了几篇关于这个主题的文章,但我仍然不清楚Promise.reject与抛出错误之间是否存在差异。 For example, 例如,

Using Promise.reject 使用Promise.reject

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            return Promise.reject(new PermissionDenied());
        }
    });

Using throw 用投掷

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            throw new PermissionDenied();
        }
    });

My preference is to use throw simply because it is shorter, but was wondering if there is any advantage of one over the other. 我倾向于使用throw只是因为它更短,但是想知道是否有一个优于另一个。


#1楼

参考:https://stackoom.com/question/2GKgB/JavaScript承诺-拒绝与抛出


#2楼

Yes, the biggest difference is that reject is a callback function that gets carried out after the promise is rejected, whereas throw cannot be used asynchronously. 是的,最大的区别是reject是一个回调函数,它在promise被拒绝后执行,而throw不能异步使用。 If you chose to use reject, your code will continue to run normally in asynchronous fashion whereas throw will prioritize completing the resolver function (this function will run immediately). 如果您选择使用reject,您的代码将继续以异步方式正常运行,而throw将优先完成解析器功能(此功能将立即运行)。

An example I've seen that helped clarify the issue for me was that you could set a Timeout function with reject, for example: 我见过的一个例子帮助我澄清了问题,你可以设置一个带有拒绝的超时功能,例如:

new Promise(_, reject) {
 setTimeout(reject, 3000);
});

The above could would not be possible to write with throw. 以上可能无法用throw写。

In your small example the difference in indistinguishable but when dealing with more complicated asynchronous concept the difference between the two can be drastic. 在你的小例子中,差异无法区分,但在处理更复杂的异步概念时,两者之间的差异可能是极大的。


#3楼

There is no advantage of using one vs the other, but, there is a specific case where throw won't work. 使用一个与另一个没有任何优势,但是,有一个特定的情况, throw不起作用。 However, those cases can be fixed. 但是,这些案件可以修复。

Any time you are inside of a promise callback, you can use throw . 每当你进入promise回调时,你都可以使用throw However, if you're in any other asynchronous callback, you must use reject . 但是,如果您处于任何其他异步回调中,则必须使用reject

For example, this won't trigger the catch: 例如,这不会触发捕获:

 new Promise(function() { setTimeout(function() { throw 'or nah'; // return Promise.reject('or nah'); also won't work }, 1000); }).catch(function(e) { console.log(e); // doesn't happen }); 

Instead you're left with an unresolved promise and an uncaught exception. 相反,你留下了未解决的承诺和未被捕获的异常。 That is a case where you would want to instead use reject . 在这种情况下,您可能希望改为使用reject However, you could fix this by promisifying the timeout: 但是,你可以通过宣告超时来解决这个问题:

 function timeout(duration) { // Thanks joews return new Promise(function(resolve) { setTimeout(resolve, duration); }); } timeout(1000).then(function() { throw 'worky!'; // return Promise.reject('worky'); also works }).catch(function(e) { console.log(e); // 'worky!' }); 


#4楼

Another important fact is that reject() DOES NOT terminate control flow like a return statement does. 另一个重要的事实是, reject()终止控制流return的语句一样。 In contrast throw does terminate control flow. 相比之下, throw会终止控制流程。

Example: 例:

 new Promise((resolve, reject) => { throw "err"; console.log("NEVER REACHED"); }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED")); 

vs VS

 new Promise((resolve, reject) => { reject(); // resolve() behaves similarly console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED")); 


#5楼

TLDR: A function is hard to use when it sometimes returns a promise and sometimes throws an exception. TLDR: 当函数有时返回一个promise并且有时会引发异常时,它很难使用。 When writing an async function, prefer to signal failure by returning a rejected promise 在编写异步函数时,更喜欢通过返回被拒绝的promise来表示失败

Your particular example obfuscates some important distinctions between them: 您的特定示例模糊了它们之间的一些重要区别:

Because you are error handling inside a promise chain, thrown exceptions get automatically converted to rejected promises. 因为你是一个承诺链的错误处理,抛出的异常都会自动转换为拒绝承诺。 This may explain why they seem to be interchangeable - they are not. 这可以解释为什么它们似乎是可以互换的 - 它们不是。

Consider the situation below: 考虑以下情况:

checkCredentials = () => {
    let idToken = localStorage.getItem('some token');
    if ( idToken ) {
      return fetch(`https://someValidateEndpoint`, {
        headers: {
          Authorization: `Bearer ${idToken}`
        }
      })
    } else {
      throw new Error('No Token Found In Local Storage')
    }
  }

This would be an anti-pattern because you would then need to support both async and sync error cases. 这将是一种反模式,因为您需要同时支持异步和同步错误情况。 It might look something like: 它可能看起来像:

try {
  function onFulfilled() { ... do the rest of your logic }
  function onRejected() { // handle async failure - like network timeout }
  checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
  // Error('No Token Found In Local Storage')
  // handle synchronous failure
} 

Not good and here is exactly where Promise.reject ( available in the global scope ) comes to the rescue and effectively differentiates itself from throw . 不好,这正是Promise.reject (在全球范围内可用)拯救并有效区别于throw The refactor now becomes: 重构现在变成:

checkCredentials = () => {
  let idToken = localStorage.getItem('some_token');
  if (!idToken) {
    return Promise.reject('No Token Found In Local Storage')
  }
  return fetch(`https://someValidateEndpoint`, {
    headers: {
      Authorization: `Bearer ${idToken}`
    }
  })
}

This now lets you use just one catch() for network failures and the synchronous error check for lack of tokens: 现在,您只需使用一个catch()进行网络故障, 使用缺少令牌的同步错误检查:

checkCredentials()
      .catch((error) => if ( error == 'No Token' ) {
      // do no token modal
      } else if ( error === 400 ) {
      // do not authorized modal. etc.
      }

#6楼

An example to try out. 尝试的一个例子。 Just change isVersionThrow to false to use reject instead of throw. 只需将isVersionThrow更改为false即可使用reject而不是throw。

 const isVersionThrow = true class TestClass { async testFunction () { if (isVersionThrow) { console.log('Throw version') throw new Error('Fail!') } else { console.log('Reject version') return new Promise((resolve, reject) => { reject(new Error('Fail!')) }) } } } const test = async () => { const test = new TestClass() try { var response = await test.testFunction() return response } catch (error) { console.log('ERROR RETURNED') throw error } } test() .then(result => { console.log('result: ' + result) }) .catch(error => { console.log('error: ' + error) }) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值