Bri*_*unt 45 jquery promise jquery-deferred q es6-promise
@Domenic有一篇关于jQuery延迟对象失败的非常详尽的文章:你错过了Point of Promises.在其中,Domenic突出了jQuery承诺的一些失败,与其他包括Q,when.js,RSVP.js和ES6承诺相比.
我离开了Domenic的文章,认为jQuery承诺在概念上有一个固有的失败.我试图把这个例子放在这个概念上.
我认为jQuery实现有两个问题:
.then
方法不可链接换一种说法
promise.then(a).then(b)
Run Code Online (Sandbox Code Playgroud)
jQuery将调用a
随后b
的时候promise
满足.
由于.then
在其他promise库中返回一个新的promise,它们的等价物将是:
promise.then(a)
promise.then(b)
Run Code Online (Sandbox Code Playgroud)
另一个问题似乎是异常处理,即:
try {
promise.then(a)
} catch (e) {
}
Run Code Online (Sandbox Code Playgroud)
Q中的等价物是:
try {
promise.then(a).done()
} catch (e) {
// .done() re-throws any exceptions from a
}
Run Code Online (Sandbox Code Playgroud)
在jQuery中,当a
catch块失败时异常抛出并出现气泡.在其他承诺中,任何异常a
将被传递到.done
或.catch
或其他异步捕获.如果没有任何promise API调用捕获异常,它就会消失(因此Q最佳实践,例如使用.done
释放任何未处理的异常).
上述问题是否涵盖了jQuery实现承诺的问题,还是我误解或遗漏了问题?
编辑 此问题与jQuery <3.0; 从 jQuery 3.0开始,alpha jQuery是Promises/A +兼容的.
Ben*_*aum 52
更新:jQuery 3.0修复了下面列出的问题.这是真正的Promises/A +兼容.
也就是说,自从撰写这篇文章以来,jQuery做出了很大的努力,成为更多的Promises/Aplus投诉,他们现在有了一个链接的.then方法.
因此,即使在jQuery returnsPromise().then(a).then(b)
for promise返回函数a
并且b
将按预期工作,在继续前进之前展开返回值.正如这个小提琴所示:
function timeout(){
var d = $.Deferred();
setTimeout(function(){ d.resolve(); },1000);
return d.promise();
}
timeout().then(function(){
document.body.innerHTML = "First";
return timeout();
}).then(function(){
document.body.innerHTML += "<br />Second";
return timeout();
}).then(function(){
document.body.innerHTML += "<br />Third";
return timeout();
});
Run Code Online (Sandbox Code Playgroud)
没有办法将jQuery承诺标记为"已处理",即使你解决了它,与catch不同.这使得jQuery中的拒绝固有地破坏并且非常难以使用,就像同步一样try/catch
.
你能猜出这里有什么记录吗?(小提琴)
timeout().then(function(){
throw new Error("Boo");
}).then(function(){
console.log("Hello World");
},function(){
console.log("In Error Handler");
}).then(function(){
console.log("This should have run");
}).fail(function(){
console.log("But this does instead");
});
Run Code Online (Sandbox Code Playgroud)
如果你猜对了"uncaught Error: boo"
你是对的.jQuery promises 不是安全的.与Promises/Aplus承诺不同,他们不会让你处理任何抛出的错误.拒绝安全怎么办?(小提琴)
timeout().then(function(){
var d = $.Deferred(); d.reject();
return d;
}).then(function(){
console.log("Hello World");
},function(){
console.log("In Error Handler");
}).then(function(){
console.log("This should have run");
}).fail(function(){
console.log("But this does instead");
});
Run Code Online (Sandbox Code Playgroud)
以下日志"In Error Handler" "But this does instead"
- 根本没有办法处理jQuery promise拒绝.这与您期望的流程不同:
try{
throw new Error("Hello World");
} catch(e){
console.log("In Error handler");
}
console.log("This should have run");
Run Code Online (Sandbox Code Playgroud)
使用像Bluebird和Q这样的Promises/A +库,以及您对实用性的期望是什么.这是巨大的,投掷安全是承诺的一大卖点.这里是Bluebird在这种情况下,正确的行动.
如果底层的promise已经解决,jQuery将立即执行传递的函数而不是推迟它,因此代码的行为会有所不同,具体取决于我们是否将处理程序附加到已拒绝的处理程序已经解决.这有效地释放了Zalgo并且可能导致一些最痛苦的错误.这创建了一些最难调试的bug.
如果我们看下面的代码:( 小提琴)
function timeout(){
var d = $.Deferred();
setTimeout(function(){ d.resolve(); },1000);
return d.promise();
}
console.log("This");
var p = timeout();
p.then(function(){
console.log("expected from an async api.");
});
console.log("is");
setTimeout(function(){
console.log("He");
p.then(function(){
console.log("?????Z???????A?????L????????G???????O???!????? *");
});
console.log("Comes");
},2000);
Run Code Online (Sandbox Code Playgroud)
我们可以观察到这么危险的行为,setTimeout
等待原始超时结束,所以jQuery切换它的执行顺序,因为...谁喜欢不会导致堆栈溢出的确定性API?这就是为什么Promises/A +规范要求promises总是延迟到事件循环的下一次执行.
值得一提的是像Bluebird这样更新更强大的承诺库(以及实验性的When)并不.done
像Q那样需要在链的末端,因为他们自己找出了未处理的拒绝,它们也比jQuery承诺或Q承诺快得多.
归档时间: |
|
查看次数: |
14342 次 |
最近记录: |