jQuery $ .Deferred(jQuery 1.x/2.x)固有的问题 [英] Problems inherent to jQuery $.Deferred (jQuery 1.x/2.x)

查看:95
本文介绍了jQuery $ .Deferred(jQuery 1.x/2.x)固有的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

@Domenic关于jQuery延迟对象的失败有一篇非常详尽的文章:您错过了承诺的重点.与其他内容相比,Domenic重点介绍了jQuery Promise的一些失败,包括 Q ,when.js,RSVP.js和ES6 Promise.

@Domenic has a very thorough article on the failings of jQuery deferred objects: You're missing the Point of Promises. In it Domenic highlights a few failings of jQuery promises in comparison to others including Q, when.js, RSVP.js and ES6 promises.

从Domenic的文章中我感觉到jQuery承诺从概念上讲是固有的失败.我正在尝试举例说明这个概念.

I walk away from Domenic's article feeling that jQuery promises have an inherent failing, conceptually. I am trying to put examples to the concept.

我认为jQuery实现有两个问题:

I gather there are two concerns with the jQuery implementation:

换句话说

promise.then(a).then(b)

promise完成时,jQuery将先调用a,然后调用b.

jQuery will call a then b when the promise is fulfilled.

由于.then在其他promise库中返回新的promise,因此它们的等效项为:

Since .then returns a new promise in the other promise libraries, their equivalent would be:

promise.then(a)
promise.then(b)

2.异常处理在jQuery中冒泡.

另一个问题似乎是异常处理,即:

2. The exception handling is bubbled in jQuery.

The other issue would seem to be exception handling, namely:

try {
  promise.then(a)
} catch (e) {
}

Q中的等​​价物为:

The equivalent in Q would be:

try {
  promise.then(a).done()
} catch (e) {
   // .done() re-throws any exceptions from a
}

在jQuery中,当a未能到达catch块时,异常引发并冒泡.在另一个承诺中,a中的任何异常都将传递到.done.catch或其他异步捕获.如果没有一个Promise API调用都捕获到异常,则异常消失(因此,Q的最佳实践,例如使用.done释放任何未处理的异常).

In jQuery the exception throws and bubbles when a fails to the catch block. In the other promises any exception in a would be carried through to the .done or .catch or other async catch. If none of the promise API calls catch the exception it disappears (hence the Q best-practice of e.g. using .done to release any unhandled exceptions).

 

以上问题是否涵盖了jQuery实现promise的问题,还是我误解或错过了问题?

Do the problems above cover the concerns with the jQuery implementation of promises, or have I misunderstood or missed issues?

编辑 .该问题与jQuery< 3.0;从 jQuery 3.0 alpha版本开始 jQuery符合Promises/A +.

Edit This question relates to jQuery < 3.0; as of jQuery 3.0 alpha jQuery is Promises/A+ compliant.

推荐答案

更新:jQuery 3.0已修复了以下概述的问题.它确实符合Promises/A +.

Update: jQuery 3.0 has fixed the problems outlined below. It is truly Promises/A+ compliant.

也就是说,自从这篇文章被编写以来,jQuery做出了巨大的努力来解决更多Promises/Aplus投诉,并且他们现在有了一个.then方法进行链接.

That said, since the article was written jQuery made significant efforts to be more Promises/Aplus complaint and they now have a .then method that chains.

因此,即使在jQuery returnsPromise().then(a).then(b)中,对于promise返回函数ab也会按预期工作,在继续前进之前展开返回值.如下所示小提琴:

So even in jQuery returnsPromise().then(a).then(b) for promise returning functions a and b will work as expected, unwrapping the return value before continuing forward. As illustrated in this fiddle:

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 Prom标记为已处理".这使得jQuery中的拒绝操作固有地被破坏并且很难使用,与同步try/catch完全不同.

However, the two huge problems with jQuery are error handling and unexpected execution order.

Error handling

There is no way to mark a jQuery promise that rejected as "Handled", even if you resolve it, unlike catch. This makes rejections in jQuery inherently broken and very hard to use, nothing like synchronous try/catch.

您能猜出这里记录了什么吗? (小提琴)

Can you guess what logs here? (fiddle)

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承诺不安全.他们不会像Promises/Aplus的承诺那样让您处理任何引发的错误.拒绝安全怎么办? (小提琴)

If you guessed "uncaught Error: boo" you were correct. jQuery promises are not throw safe. They will not let you handle any thrown errors unlike Promises/Aplus promises. What about reject safety? (fiddle)

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 Promise拒绝.这与您期望的流程不同:

The following logs "In Error Handler" "But this does instead" - there is no way to handle a jQuery promise rejection at all. This is unlike the flow you'd expect:

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

使用Promises/A +库(例如Bluebird和Q)得到的流程是什么,以及期望有用的内容.这是巨大,并且抛出安全性是承诺的一大卖点.这是在这种情况下蓝鸟的行为正确的.

Which is the flow you get with Promises/A+ libraries like Bluebird and Q, and what you'd expect for usefulness. This is huge and throw safety is a big selling point for promises. Here is Bluebird acting correctly in this case.

jQuery将立即执行传递的函数 ,而不是在基础promise已解决的情况下推迟执行该函数,因此代码的行为将有所不同,具体取决于我们是否将promise附加到已解决的已拒绝对象上的promise.这实际上是释放Zalgo ,并可能导致某些最痛苦的错误.这会创建一些最难调试的错误.

jQuery will execute the passed function immediately rather than deferring it if the underlying promise already resolved, so code will behave differently depending on whether the promise we're attaching a handler to rejected already resolved. This is effectively releasing Zalgo and can cause some of the most painful bugs. This creates some of the hardest to debug bugs.

如果我们看下面的代码:(小提琴)

If we look at the following code: (fiddle)

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?这就是Promises/A +规范要求将承诺始终推迟到事件循环的下一次执行的原因.

We can observe that oh so dangerous behavior, the setTimeout waits for the original timeout to end, so jQuery switches its execution order because... who likes deterministic APIs that don't cause stack overflows? This is why the Promises/A+ specification requires that promises are always deferred to the next execution of the event loop.

值得一提的是,像Q那样,像Bluebird这样的更强大的Promise库(以及实验性的When)在链的末尾不需要.done,因为它们自己找出未处理的拒绝,它们也比jQuery快得多许诺或Q许诺.

Worth mentioning that newer and stronger promise libraries like Bluebird (and experimentally When) do not require .done at the end of the chain like Q does since they figure out unhandled rejections themselves, they're also much much faster than jQuery promises or Q promises.

这篇关于jQuery $ .Deferred(jQuery 1.x/2.x)固有的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆