【问题标题】:.catch function doesnt catch rejected value.catch 函数不捕获被拒绝的值
【发布时间】:2017-12-13 01:34:14
【问题描述】:

大家好!

我使用 Node.js v8.5.0。 这是我在 Node.js 中的代码(简化版):

    // function that returns promise
    const request = (url) =>
      new Promise((resolve, reject) => {
        superagent
          .get(url)
          .end((err, res) => {
            if (err || !res.ok) {
              reject(err);
              return;
            }

            resolve(res);
          })
      })

   // function that add .then and .catch to promise   
   const to = promise =>
    promise
    .then((data) => [null, data])
    .catch((err) => [err]);

   // making request 
   let [err, result] = await to(request());

当我请求并发生一些错误时,.catch 函数不会捕获被拒绝的值,我会收到类似 Unhandled Promise Rejection 的错误。 但是,其实我在promise中添加了.catch函数。

有人知道这里有什么问题吗? 感谢帮助!

【问题讨论】:

  • 确实返回新的承诺
  • 但是promise与请求方法没有关联,是吗?
  • 您为什么不返回superagent 承诺?创建一个新的承诺是一种反模式

标签: javascript node.js promise


【解决方案1】:

超级代理请求已经返回了一个承诺,因此请改用它

const request = (url) => superagent.get(url).then(res=> {/*transform res**/ return res})

【讨论】:

  • ...这可能也是发生未处理拒绝的原因 - 这个超级代理承诺是被拒绝且未处理的承诺,而不是 new Promise 确实有一个 .catch 链接到它。 (当然这听起来像是一个超级代理错误,调用 .end() 应该将承诺标记为已处理)。
  • .then 函数在我的代码中运行良好。但是当发生错误时.catch 函数不会捕获错误。这很奇怪,因为实际上它是通过to 函数添加到承诺中的。
  • 也许你有其他反模式承诺包装了其他东西也返回承诺,正如 bergi 指出的那样,这是另一个未处理的链中的承诺
  • 我找到了一些关于这个问题的解释。请阅读此内容stackoverflow.com/a/41180264/5441891@daskh-gupta 说:不同之处在于您不将 .catch(...) 作为链处理,而是作为单独的处理。由于某种原因,Java Script 引擎将其视为没有未处理的 Promise 拒绝的 Promise
  • 但是,您不是以与问题中所示相同的方式链接捕获物吗?有问题的代码与您提供的链接中的第二个示例不同。你的链条是正确的
【解决方案2】:

您提供的代码没有这种行为,但我熟悉 uncaught in promise 警告。

如果你想稍后捕获一个promise的错误,你必须先捕获它,然后在捕获它之前返回promise。

下面的内容会给你未曾被承诺的警告:

var failPromise = val => Promise.reject(val);
var to = async promise => promise.then(val=>[null,val]).catch(err=>[err]);
var p = failPromise(88);
//later you will catch the error
setTimeout(()=>to(p).then(val=>console.log("resolved to:",val)),100);

但如果你稍微改变一下,你就不会了

var failPromise = val => {
  const p = Promise.reject(val);
  p.catch(ignore=>ignore);
  return p;//return the promise that did not have the catch
};
var to = async promise => promise.then(val=>[null,val]).catch(err=>[err]);
var p = failPromise(88);
//later you will catch the error
setTimeout(()=>to(p).then(val=>console.log("resolved to:",val)),100);

如前所述;您的请求方法应该只返回 superagent 返回的承诺,但是您可以稍后在没有错误(警告)的情况下捕获拒绝:

const request = (url) => {
  const p = superagent
    .get(url);
  p.catch(ignore=>ignore);
  return p;
})

如果你想知道为什么你没有兑现承诺;这是因为您在队列中而不是在堆栈中捕获了拒绝。堆栈和队列解释here

在堆栈中捕获的示例不会在控制台中导致错误,但随后会返回没有捕获的承诺。根据您要在队列中捕获它的距离,它可能仍然会给您错误,但在提供的代码中不会。

【讨论】:

  • 没有任何理由必须自己捕获超级代理承诺。它将被捕获在 OP 代码中显示的链中
  • @charlietfl 代码 OP 发布的代码显然不是给他他所说的错误的代码,也不是 OP 描述的行为方式。如果 OP 会测试提供的代码,那么 OP 会知道它没有。更新了解释未捕获承诺来自何处的答案。
  • 接受。还有一些其他操作没有显示给我们
  • @charlietfl 我实际上犯了一个错误,将 p 分配给 promise.catch 而不是 promise,因此您以后永远无法捕获它(在队列中的代码中)。修复了更新答案中的问题。
  • 感谢所有回答
猜你喜欢
  • 1970-01-01
  • 2016-06-21
  • 2022-01-05
  • 2019-08-10
  • 2018-07-04
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多