【问题标题】:Catching errors with Q.deferred使用 Q.deferred 捕获错误
【发布时间】:2016-08-09 11:34:20
【问题描述】:

我有一个 nodeJS 项目,我希望在其中使用异步函数。也就是说,我正在使用Q 库。

我有一个名为 someFunction() 的函数,我希望返回一个 Promise。使用 then 函数,我可以像这样检查承诺是被解决还是被拒绝:

    someFunction()
    .then(
      function(results) {
        console.log("Success!");
      },
      function (error) {
        console.log("An error occurred, and I would wish to log it for example");
      }
    );

我对上述函数的直觉期望是,错误函数会捕获所有可能的错误。因此,如果在 someFunction 内部引发了一些异常,我可以放心,错误函数将运行('then' 之后的第二个函数)。但好像不是这样的。

例如,假设 someFunction 会这样定义:

function someFunction() {
  var deferred = Q.defer();
  throw new Error("Can't bar.");

  deferred.resolve("success");
}

现在,如果我像在上面的代码块中那样调用函数 someFunction(),它不会运行错误函数。这是为什么?承诺 Q.deferred 的部分重点不是捕获错误吗?为什么我要手动拒绝发生的每个错误?我知道我可以将 someFunction 的全部内容设置为 try/catch 子句,然后拒绝延迟,但这感觉太不对了!一定有更好的方法,我知道你们中的一些人肯定知道!

有了这些信息,我开始思考 deferred.reject 和 deferred.resolve 到底应该用在哪里?它甚至意味着捕获异常吗?我真的应该手动检查所有错误案例,然后调用 deferred.reject 吗?我很想知道应该如何专业地处理这件事。

【问题讨论】:

  • 这就是为什么 a) 不应该抛出任何返回承诺的函数 b) 你 should prefer the promise constructor over deferreds
  • 但是你怎么能保证一个没有返回承诺的函数不会抛出呢?我的意思是您可能正在使用一些外部库?但是,我认为您可能走在正确的轨道上,也许您可​​以提供答案。
  • 通过调试/消除错误,并将可能抛出的代码包装在 try..catch 块中并处理错误;也许通过返回Q.reject(error)

标签: javascript node.js q deferred


【解决方案1】:

Q对成功和错误有特定的功能,所以使用:

deferred.reject("error");

不要抛出异常。

接下来是 someFunction 必须返回 Promise 才能在您使用时使用它:

function someFunction() {

  var deferred = Q.defer();

  try{

  //some Asynchronous code
  deferred.resolve("success");


  }catch(e){

    deferred.reject(e.message);

  }

  return deffered.promise; //return promise to use then
}

【讨论】:

  • 是的,我知道。但是,如果我在 someFunction() 中执行代码,会引发错误怎么办?然后唯一的选择是将整个 someFunction 包装在 try/catch 子句中,这感觉不对……在 someFunction 中,我可以使用一些可能导致错误的外部库。
【解决方案2】:

因为承诺不是魔法。他们不会以某种方式神奇地捕获错误。它们捕获它们,因为它们将对回调的调用包装在 try..catch-blocks 中,以将错误转换为被拒绝的 Promise。

如果您希望 Promise 链处理错误,请将函数调用放入 Promise 链中:Q.resolve().then(someFunction).then(...)。 现在 someFunction 中发生的任何同步错误都可以在下面的 then 中处理。

顺便说一句:如果您使用 Q.defer(),并且您没有处理一些回调样式的 API,那么您这样做肯定是错误的。搜索 Deferred-antipattern。

【讨论】:

  • 您能否详细说明在这种情况下回调样式 API 的含义?我正在处理一个肥皂 API。
【解决方案3】:

它不会运行错误函数。这是为什么呢?

因为您同步抛出异常,而不是返回承诺。 Which you never should.

promise Q.deferred 的部分点不是捕捉错误吗?

没有。 thencatch 在它们的回调中隐式捕获异常,而延迟则不会——它们只是一个 (deprecated) API 来创建承诺。

我为什么要手动拒绝发生的每个错误?

因为异步错误无论如何都会被传递给回调,而不是被抛出。

我知道我可以将 someFunction 的全部内容设置为 try/catch 子句,然后拒绝 deferred,但这感觉太不对了!一定有更好的办法!

有:Q.Promise constructor,标准 (ES6) Promise 创建 API。它的好处是能够从 executor 函数中捕获同步异常:

function someFunction() {
  return new Q.Promise(function(resolve) {
    throw new Error("Can't bar.");
    resolve("success");
  });
}

【讨论】:

    【解决方案4】:

    除非您在 try/catch 块中捕获错误,否则抛出错误将停止代码执行(并将关闭节点)。

    可以使用deferred.reject(error) 将来自请求的已处理错误传递给.catch 链。代码错误和自定义抛出的错误需要在try/catch里面处理,这是处理此类错误的正确方式。

    function someFunction() {
      var deferred = Q.defer();
      deferred.reject("Can't bar.");
      // or
      try {
        throw new Error("Can't bar.");
      }
      catch(err) {
        deferred.reject("Can't bar.");
      }
    
      deferred.resolve("success");
    }
    

    【讨论】:

      猜你喜欢
      • 2018-03-25
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 2019-05-18
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多