为了账号安全,请及时绑定邮箱和手机立即绑定

jQuery$.延迟固有的问题(jQuery 1.x/2.x)

jQuery$.延迟固有的问题(jQuery 1.x/2.x)

慕容森 2019-07-03 16:46:45
jQuery$.延迟固有的问题(jQuery 1.x/2.x)有一篇关于jQuery延迟对象失败的非常详尽的文章:你错过了承诺的要点..在这篇文章中,多梅尼奇强调了jQuery承诺与其他承诺相比的一些缺点,包括Q、RSVP.js和ES6承诺。我离开了多梅尼奇的文章,觉得jQuery承诺在概念上有一个固有的缺陷。我想举例说明这个概念。我认为jQuery实现有两个关注点:1..then方法是不可链接的。换句话说promise.then(a).then(b)jQuery将调用a然后b当promise都实现了。自.then在其他承诺库中返回一个新的承诺,它们的等效值是:promise.then(a)promise.then(b)2.jQuery中出现异常处理。另一个问题似乎是异常处理,即:try {   promise.then(a)} catch (e) {}在Q中相当于:try {   promise.then(a).done()} catch (e) {    // .done() re-throws any exceptions from a}在jQuery中,当a捕获块失败。在另一个承诺中,任何例外a会被带到.done或.catch或者其他异步捕获。如果所有的承诺API调用都没有捕获异常,那么它就消失了(因此,使用.done若要释放任何未处理的异常,请执行以下操作。 上面的问题是否涵盖了jQuery承诺实现的问题,还是我误解或忽略了一些问题?编辑此问题涉及jQuery<3.0;jQuery3.0alphajQuery是答应/A+兼容的。
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

jQuery3.0修复了下面概述的问题。这是真正的承诺/A+符合。

是的,jQuery承诺存在严重的固有问题。

尽管如此,由于这篇文章是写的,jQuery做出了很大的努力,希望成为更多的承诺/Aplus抱怨,现在他们有了一种.然后链接的方法。

所以即使在jQuery中returnsPromise().then(a).then(b)用于承诺返回函数ab将按预期工作,在继续前进之前展开返回值。如图所示小提琴:

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

然而,这两个巨量jQuery的问题是错误处理和意外执行顺序。

错误处理

与CATCH不同,即使您解决了jQuery承诺,也无法将其标记为“已处理”。这使得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"); });

如果你猜到"uncaught Error: boo"你是对的。jQuery的承诺是不扔保险柜..它们将不允许您处理任何抛出的错误,而不是承诺/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"); });

以下日志"In Error Handler" "But this does instead"-根本无法处理jQuery承诺的拒绝。这与您所期望的流程不同:

try{
   throw new Error("Hello World");} catch(e){
   console.log("In Error handler");}console.log("This should have run");

这就是承诺/A+库(如Bluebird和Q)的流程,以及您期望的有用性。这是巨量抛出安全是承诺的一个重要卖点。这是蓝鸟在这种情况下动作正确.

执行命令

jQuery将执行传递的函数。立马如果底层承诺已经解决,而不是推迟它,那么代码的行为将有所不同,这取决于我们向拒绝的处理程序附加的承诺是否已经解决。这是有效的释放扎尔戈会引起一些最痛苦的虫子。这就产生了一些最难调试的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);

我们可以观察到,哦,如此危险的行为,setTimeout等待原始超时结束,因此jQuery切换其执行顺序,因为.。谁喜欢不会导致堆栈溢出的确定性API?这就是为什么允诺/A+规范要求承诺总是被推迟到事件循环的下一次执行。

旁注

值得一提的是,更新更强的承诺库,如蓝鸟库(以及实验时)不需要.done在链的末尾,就像Q一样,因为它们自己发现了未处理的拒绝,它们也比jQuery承诺或Q承诺要快得多。


查看完整回答
反对 回复 2019-07-03
?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

这几乎不是一个黑暗的巫毒把戏,没有必要去寻找它的来源。自从jQuery 1.8发布以来,文档已经读过了"these filter functions can return a new value to be passed along to the promise's .done() or .fail() callbacks, or they can return another observable object (Deferred, Promise, etc) which will pass its resolved / rejected status and values to the promise's callbacks"..因此,并不是一个“大问题”,如果你活着,实际上根本不是一个问题

查看完整回答
反对 回复 2019-07-03
  • 3 回答
  • 0 关注
  • 382 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信