我读过几篇关于这个主题的文章,但我仍然不清楚《承诺》和《承诺》之间是否有区别。拒绝与抛出错误。例如,

使用Promise.reject

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

使用扔

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

我更喜欢使用throw,因为它更短,但我想知道其中一种比另一种是否有任何优势。


当前回答

另一个重要的事实是reject()不会像return语句那样终止控制流。相反,throw会终止控制流。

例子:

new Promise((resolve, reject) => { 把“犯错”; console.log(“从来没有达到”); }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));

vs

new Promise((resolve, reject) => { 拒绝();// resolve()行为类似 console.log(“总是达到“);// "REJECTED"将在此之后打印 }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));

其他回答

TLDR:当函数有时返回承诺,有时抛出异常时,它很难使用。在编写异步函数时,最好通过返回一个被拒绝的承诺来表示失败

你的例子混淆了它们之间的一些重要区别:

因为您是在承诺链内进行错误处理,抛出的异常会自动转换为被拒绝的承诺。这也许可以解释为什么它们看起来是可以互换的——实际上并非如此。

考虑以下情况:

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')
    }
  }

这将是一种反模式,因为您将需要同时支持异步和同步错误情况。它可能看起来像这样:

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
} 

不太好,这正是承诺。Reject(在全局范围内可用)来拯救并有效地将自己与throw区分开来。重构现在变成:

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}`
    }
  })
}

这现在让你只使用一个catch()来处理网络故障,并对缺乏令牌进行同步错误检查:

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

区别在于三元运算符

你可以使用

return condition ? someData : Promise.reject(new Error('not OK'))

你不能用

return condition ? someData  : throw new Error('not OK')

一个要尝试的例子。只需将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) })

使用一种方法与另一种方法相比没有任何优势,但是,在特定的情况下,throw将不起作用。然而,这些情况是可以解决的。

任何时候在promise回调中,都可以使用throw。然而,如果你在任何其他异步回调中,你必须使用拒绝。

例如,这不会触发catch:

新承诺(函数(){ setTimeout(函数(){ 抛出'or nah'; // return承诺。拒绝(或不);也不管用 }, 1000); }) .catch(函数(e) { console.log (e);//不会发生 });

相反,留给您的是一个未解决的承诺和一个未捕获的异常。在这种情况下,您应该使用reject。但是,您可以通过两种方式解决这个问题。

通过在超时内使用原来的Promise的拒绝函数:

new Promise(function(resolve, reject) { setTimeout(function() { 拒绝(“或否”); }, 1000); }).catch(function(e) { 控制台.log(e);工程! });

通过承诺超时:

function timeout(duration){//谢谢joews 返回新的承诺(函数(resolve) { setTimeout(解决,持续时间); }); } 超时(1000)(函数(){ 把“成功!”; // return Promise.reject('work ');同样适用 }) .catch(函数(e) { console.log (e);/ /“成功!” });

是的,最大的区别是reject是在promise被拒绝后执行的回调函数,而throw不能异步使用。如果你选择使用reject,你的代码将继续以异步方式正常运行,而throw将优先完成解析器函数(该函数将立即运行)。

我看到的一个例子帮助我澄清了这个问题,你可以用reject设置Timeout函数,例如:

新承诺(兑现,兑现)=> setTimeout() = >{拒绝(“err味精);控制台日志。(‘吃’)的,1000); 回收回路(“后悔”) }) 然后(o) => console.log(“RESOLVED”,o) .catch(o) => console.log(“reject”,o);

上面的代码不能用throw来写。

尝试{ new Promise((resolve, reject) => { setTimeout(()=>{抛出新的错误('err msg')}, 1000); 返回resolve('ret val') }) .then((o) => console.log("RESOLVED", o)) .catch((o) => console.log("REJECTED", o)); }捕捉(o) { console.log(“忽略”,o) }

在OP的小例子中,差异是难以区分的,但当处理更复杂的异步概念时,两者之间的差异可能是巨大的。