【问题标题】:Confuse about error and reject in Promise在 Promise 中混淆错误和拒绝
【发布时间】:2016-05-18 21:25:03
【问题描述】:

全部:

我对 JS Promise 还是很陌生,当谈到 Promise 链接时有一个困惑,比如说我有一个类似的 Promise 链接:

var p = new Promise(function(res, rej){
})
.then(
    function(data){
    }, 
    function(err){
    })
.then(
    function(data){
    }, 
    function(err){
    })
.catch(
    function(err){
    })

让我感到困惑的是:

  1. 什么时候调用函数(err),什么时候调用catch?
  2. then中如何解决和拒绝?

谢谢

【问题讨论】:

  • 我认为this answer会帮助你
  • @Bergi 谢谢,所以从你答案中的图表来看,错误可以随时引导解决函数或拒绝下一个链接 the() 的函数,这取决于我使用返回值还是抛出错误,对吗?
  • 是的,完全正确。什么都不做(返回undefined)但希望下一个catch 也能得到错误的人通常不会想到这一点,他们需要重新抛出它。
  • @Bergi 谢谢,所以我能否确保无论任何级别的链接 then() 发生什么错误,catch 都会处理异常,我能想到的唯一丑陋的方法是继续在拒绝函数中使用 throw那么,有没有更好的方法来处理这个问题?
  • 只需省略你传递给then的onreject回调,拒绝将自动传递。

标签: javascript promise


【解决方案1】:

使用 Promise 的公式是:

var p = new Promise(function(resolve, reject) {

  var condition = doSomething();

  if (condition) {
    resolve(data);
  } else {
    reject(err);
  }

});

.catch 没有什么特别之处,它只是.then (undefined, func) 的糖,但.catch 更清楚地表明它纯粹是一个错误处理程序。

如果Promise 未解决且其中未提供拒绝回调,则它会跳至链中包含拒绝回调的下一个.then。拒绝回调是reject(err)

更详细的解释见:Javascript Promises - There and Back again


也就是说:在您的示例中,.catch 只有在前面的拒绝回调中有错误时才会被调用。那就是 reject(err) 函数本身存在错误 - 这与前面的 Promise 未解析无关。

您基本上可以将自己限制在.catch 中位于.then 链末端的拒绝回调。任何.then 中的任何Error 都将落入.catch。但有一个微妙之处:.catch 中的任何错误都不会被捕获。

【讨论】:

  • 我相信 Promise 对象的执行器函数首先接受 RESOLVE 回调。
  • 不确定你的确切意思@BinaekSarkar。应该构造 Promise,以便只有在它成功完成任务时才解决。
  • 我的意思是 Promise 执行器函数将 RESOLVES 函数作为第一个参数。 var p = new Promise(function(reject, resolve) 应该是 var p = new Promise(function(resolve, reject)
【解决方案2】:

要知道的重要一点是 .then() 方法总是链接到一个 Promise ,它返回一个 new Promise,其值和已解决/拒绝状态是基于给它的函数返回的。

在您的示例中,如果原始 Promise 解析,那么您的第一个 .then() 中的第一个函数将使用解析的值调用。如果它返回一个值,那么 it 返回的任何值都将最终传递到 second .then() 中的第一个函数中。 catch 中的函数永远不会被调用。

如果 Promise 拒绝,您的第一个 .then() 中的第二个函数将使用被拒绝的值调用,并且它返回的任何 value 都将成为一个新的已解析 Promise 并传递给第一个函数那么你的第二个。在这里也永远不会调用 Catch。只有当 Promise 拒绝并且您继续返回被拒绝的 Promise 或在您的 function(err){} 函数中抛出错误时,您才会在调用的 catch 块中获得 function(err){}

要在 function(data){} 函数中解析,您需要做的就是返回一个值(或返回一个稍后解析的 Promise/thenable)。 要拒绝,您需要抛出一个错误,实际上导致一个错误,返回一个最终拒绝的新 Promise,或者显式返回 Promise.reject(::some value::)

要在您的function(err){} 块中解析,您需要做的就是返回一个新值。您还可以返回一个 Promise,在这种情况下,Promise 就是将返回的内容(最终解决或拒绝)。

一般来说,在同一个 .then() 中同时定义已解决和已拒绝的路径是不明智的:PROMISE.then(fn).catch(fn) 是一种更安全/更清晰的做法,因为第一个 .then() 中的任何错误都将是被抓住。但是,如果您改为使用PROMISE.then(fn, fn),则如果第一个函数中发生错误,则第二个函数不会捕获该错误:稍后链接的某些方法将不得不捕获它。

【讨论】:

  • " 如果 Promise 解决了,那么您的第一个 .then() 中的第一个函数将使用已解决的值调用"仅当已解决的值不是 promise 对象(或 thenable 对象)时才成立. “并且它返回的任何值都将成为一个新的已解决的 Promise,然后传递到您的第二个函数的第一个函数中。” 完全不正确。如果它返回的值是一个 Promise,它会调用 .then 返回的 Promise 的 then/catch 处理程序。如果它没有返回承诺,则返回的值将传递给 .then 处理程序。投反对票。
  • 我稍后会详细介绍/提及这一点,但我已经编辑以澄清起初我只是在谈论返回值的情况。 Imo,在开始时,重要的是首先要了解以下基本概念:无论 .then(fn) 中的函数 fn 返回什么,都将决定创建什么样的新 Promise(它包装了什么值)以及链接纯的、返回值的函数使用 P.then(fn1).then(fn2).then(fn3) 类似于 Promise.resolve(compose(f1,f2,f3)(Pvalue))。你也可以返回 Promises/thenables 是一个更复杂的想法,但首先涵盖基础知识是个好主意。
  • @Dtipson 谢谢,经过几次尝试,我发现这个答案对我来说最有意义。
  • Promises A+ spec 没有提到围绕 .then(onfulfill) 函数的返回值创建新的 Promise 包装器,ECMAScript 2015 specification 中也没有描述。没有为 then(fn) 函数的返回值创建新的 Promise 包装器。
  • "7. then must return a promise" 对于 onFulfilled 中的返回值,会导致 Promise Resolution Procedure “用值 x 履行 promise” 我们不是在谈论“新”Promise ((resolve,reject)=>...) 在这里,而是链中的每个步骤肯定是一个新的 Promise,因为它与它所链接的不是相同的 Promise。链中的每个步骤都可以分配一个值,传递,并有不同的东西从它链下。
【解决方案3】:
  1. 注意示例中的执行器函数

    var p = new Promise(function(res, rej){});

    不完整。提供给 Promise 构造函数的实际执行器函数必须调用其第一个参数 (res) 来解析构造的 Promise,或调用其第二个参数 (rej) 来拒绝该 Promise。这些调用通常是异步进行的,但不必在 ES6 中。

  2. 当使用 Promise 对象(或具有 .then 属性的任何对象,它是一个函数)解析承诺时,除非在解析中提供的承诺对象本身变得履行拒绝。满足的值被传递给.thenonFulfilled处理程序,被拒绝的值被传递给.thenonRejected处理程序/侦听器/回调(取决于您的术语)。

  3. 但是,当使用非承诺(类似)对象解析承诺时,作为.then 的第一个参数提供的侦听器将使用分辨率值调用。

  4. 当使用任何值拒绝承诺时,作为.then 的第二个参数或.catch 的第一个参数提供的侦听器将使用被拒绝的值调用。

  5. .catch 是使用提供的参数作为第二个参数调用.then 并省略第一个参数的委婉说法,如

    Promise.prototype.catch = function( listener) { return this.then(null, listener);};

  6. .then 注册的onFulfillonReject 函数的行为是相同的。拒绝链式承诺会引发错误。履行链式承诺返回一个非承诺值。要保持链式承诺返回一个承诺(或类似承诺)的对象。


  7. (更新)当提供给.then( onFulfill, onReject) 的参数丢失或不是函数对象时,处理相当于从以下位置提供虚拟函数:

    function onFulfill( data) { return data;}
    function onReject( err) { throw err;}
    

    这是使用单个参数调用 thencatch 时的常见情况。

【讨论】:

  • .catch 是使用提供的参数作为第二个参数并省略第一个参数调用 .then 的委婉说法。 或者换句话说,.catch(fn) === @987654343 @ - 不过,null 可以是任何非函数
  • 关于#2:当 .then 返回一个值时,它的作用类似于“映射”操作(即,它在包装的值上运行函数并返回包装返回值的 Promise)。但是当它返回一个 Promise/thenable 时,它​​的行为类似于 flatMap/chain 操作。也就是说,它不嵌套:它不是返回一个简单的 map 操作所期望的 Promise(Promise()),而是只返回内部的 Promise()。
猜你喜欢
  • 2016-09-18
  • 2021-04-21
  • 2015-06-20
  • 2016-02-19
  • 1970-01-01
  • 2019-11-05
  • 2017-05-27
  • 2016-09-25
  • 1970-01-01
相关资源
最近更新 更多