2

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

4

2 回答 2

3

从返回承诺的函数内部抛出将在返回承诺之前发生,所以,不:

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

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

如果异步函数返回 Promise,你不需要 catch 并且实际上不需要创建你自己的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!'
  });
于 2013-02-01T18:09:22.203 回答
1

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

拒绝 Deferred 并不是绝对必要的。通常,如果您需要执行一些fail代码,或者如果您需要积极地阻止某些以后的事件解决 Deferred,则通常会这样做。

很容易认为未解决/未拒绝的 Deferreds 会永远挂起。情况不一定如此。Deferred 在任何范围内都不存在对它的引用(直接或通过其承诺)时可用于垃圾收集。

也很容易认为已解决/拒绝的 Deferred 会自动进行垃圾收集。这也是不真实的。如果对 Deferred 的引用在任何范围内仍然存在,那么它仍然会存在于内存中,并且考虑到观察者方法(例如 done/fail/always/then)可能稍后被调用(并且可能会立即触发),它仍然很有用)。

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

于 2013-02-01T17:44:40.373 回答