延迟解决方案总是在try catch中

时间:2013-02-01 09:50:50

标签: javascript error-handling jquery-deferred deferred

我正在使用jQuery Deferred的独立实现(git repo)。保持问题简单,如果我在任何函数中创建var status = _.Deferred()并返回status.promise(),那么我是否必须为该函数中的所有步骤添加try catch以reject延迟错误?

2 个答案:

答案 0 :(得分:3)

在返回promise之前,将在返回promise的函数内抛出,因此,no:

function foo() {
  var status = _.Deferred();

  throw 'DOH!';

  return status.promise();  // this will never execute
}

遇到麻烦的地方是,如果在promise-returning函数中启动的异步调用可以抛出:

function bar() {
  throw 'DOH!';
}

function foo() {
  var status = _.Deferred();

  setTimeout(function () {
    status.resolve(bar());
  }, 0);

  return status.promise();
}

foo().
  fail(function () {
    // *not* invoked when bar throws
  });

在这种情况下,您需要将调用包装到bar

function bar() {
  throw 'DOH!';
}

function foo() {
  var status = _.Deferred();

  setTimeout(function () {
    try {
      status.resolve(bar());
    } catch (e) {
      status.reject(e);
    }
  }, 0);

  return status.promise();
}

foo().
  fail(function () {
    // invoked when bar throws
  });

但是,接受回调的异步函数应捕获自己的错误,并将结果或错误传递给回调。

如果异步函数改为返回promises,则不需要捕获,实际上不需要创建自己的Deferred

function bar() {
  var d = _.Deferred();

  setTimeout(function () {
    d.resolve(42);
  }, 0);

  return d.promise();
}

function foo() {
  return bar().
    then(function (result) {
      return result * 2;
    }).
    then(function (result) {
      if (result === 84) { // true
        throw 'DOH!';
      }
    ));
}

foo().
  then(function (result) {
    // *not* invoked
  }).
  fail(function (e) {
    console.log(e.message); // 'DOH!'
  });

答案 1 :(得分:1)

在javascript中,try / catch不是像Java那样的生活方式。原因是javascript在避免可预测类型的错误方面相当丰富。

拒绝延期并非绝对必要。通常,如果您需要执行一些fail代码,或者如果您需要积极阻止某些后续事件解决延迟,您将会这样做。

很有可能认为未解决/未被拒绝的Deferreds永远都会挂起。情况不一定如此。延迟变为可用于垃圾收集,在任何范围内都不存在对其的引用,无论是直接还是通过其承诺。

也很容易认为已解决/拒绝的Deferreds会自动被垃圾收集。这也是不真实的。如果对Deferred的引用仍然存在,在任何范围内,那么它仍然会存在于内存中,并且鉴于可以稍后调用观察者方法(例如,完成/失败/始终/然后)(并且可能立即触发),它仍然可以是有用的)。

简而言之,就GC而言,Deferreds就像任何其他js对象一样,尽管通常使用它们的代码结构使得很难发现它们何时可用于GC。