我正在使用 jQuery Deferred 的独立实现(git repo)。保持问题简单,如果我在任何函数中创建var status = _.Deferred()
并返回status.promise()
,那么我是否必须为该函数中reject
的所有步骤添加一个 try catch 到延迟错误?
2 回答
从返回承诺的函数内部抛出将在返回承诺之前发生,所以,不:
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!'
});
在 javascript 中,try/catch 不像 Java 那样是一种生活方式。原因是 javascript 在避免可预测类型的错误方面相当丰富。
拒绝 Deferred 并不是绝对必要的。通常,如果您需要执行一些fail
代码,或者如果您需要积极地阻止某些以后的事件解决 Deferred,则通常会这样做。
很容易认为未解决/未拒绝的 Deferreds 会永远挂起。情况不一定如此。Deferred 在任何范围内都不存在对它的引用(直接或通过其承诺)时可用于垃圾收集。
也很容易认为已解决/拒绝的 Deferred 会自动进行垃圾收集。这也是不真实的。如果对 Deferred 的引用在任何范围内仍然存在,那么它仍然会存在于内存中,并且考虑到观察者方法(例如 done/fail/always/then)可能稍后被调用(并且可能会立即触发),它仍然很有用)。
简而言之,就 GC 而言,Deferred 就像任何其他 js 对象一样,尽管通常使用它们的代码结构很难发现它们何时可用于 GC。