- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
@Domenic 有一篇关于 jQuery 延迟对象的缺点的非常详尽的文章:You're missing the Point of Promises 。在其中,Domenic 强调了 jQuery promise 与其他 promise 相比的一些缺陷,包括 Q 、when.js、RSVP.js 和 ES6 promise 。
读完 Domenic 的文章后,我感觉 jQuery Promise 在概念上有一个固有的缺陷。我正在尝试举例说明这个概念。
我认为 jQuery 实现有两个问题:
.then
方法不可链接换句话说
promise.then(a).then(b)
当 promise
实现时,jQuery 将调用 a
,然后调用 b
。
由于 .then
在其他 Promise 库中返回一个新的 Promise,它们的等价物是:
promise.then(a)
promise.then(b)
另一个问题似乎是异常处理,即:
try {
promise.then(a)
} catch (e) {
}
Q 中的等价物是:
try {
promise.then(a).done()
} catch (e) {
// .done() re-throws any exceptions from a
}
在 jQuery 中,当 a
无法捕获 block 时,异常会抛出并冒泡。在另一个 Promise 中,a
中的任何异常都将被传递到 .done
或 .catch
或其他异步捕获。如果没有一个 Promise API 调用捕获异常,它就会消失(因此 Q 最佳实践是使用 .done
来释放任何未处理的异常)。
上述问题是否涵盖了 jQuery promise 实现的问题,还是我误解或遗漏了问题?
<小时/>编辑这个问题与 jQuery < 3.0 有关;截至jQuery 3.0 alpha jQuery 符合 Promises/A+ 标准。
最佳答案
更新:jQuery 3.0 已修复下列问题。它真正符合 Promises/A+ 标准。
也就是说,自从这篇文章写完以来,jQuery 做出了巨大的努力来更好地满足 Promises/Aplus 的要求,并且他们现在有了一个 .then 链接方法。
因此,即使在 jQuery returnsPromise().then(a).then(b)
中,promise 返回函数 a
和 b
也可以工作正如预期的那样,在继续前进之前解开返回值。如本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();
});
与 catch 不同,即使您解决了它,也无法将被拒绝的 jQuery Promise 标记为“已处理”。这使得 jQuery 中的拒绝本质上被破坏并且非常难以使用,与同步 try/catch
完全不同。
你能猜出这里记录了什么吗? (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 的 promise 是不安全。与 Promises/Aplus Promise 不同,它们不会让您处理任何抛出的错误。拒绝安全怎么样? (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");
});
以下日志“在错误处理程序中”“但这确实是”
- 根本没有办法处理 jQuery promise 拒绝。这与您期望的流程不同:
try{
throw new Error("Hello World");
} catch(e){
console.log("In Error handler");
}
console.log("This should have run");
这是您使用 Bluebird 和 Q 等 Promises/A+ 库获得的流程,以及您期望的有用性。这是巨大,并且 throw 安全性是 Promise 的一大卖点。这是Bluebird acting correctly in this case .
如果底层 Promise 已经解析,jQuery 将立即执行传递的函数,而不是推迟它,因此代码的行为会有所不同,具体取决于我们附加处理程序拒绝的 Promise 是否已经解析。这实际上是releasing Zalgo并可能导致一些最痛苦的错误。这会产生一些最难调试的错误。
如果我们看下面的代码:( 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+ 规范要求 Promises 始终推迟到事件循环的下一次执行的原因。
值得一提的是,像 Bluebird 这样更新、更强大的 Promise 库(以及实验性的 When)不需要像 Q 那样在链的末尾处 .done
,因为它们自己找出未处理的拒绝,它们是也比 jQuery Promise 或 Q Promise 快得多。
关于jquery - jQuery $.Deferred (jQuery 1.x/2.x) 固有的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23744612/
在 javascript 中使用 defer 属性的正确语法是什么? 我见过有两种方式: 1: ... 2: ... 根据经验 [和我找不到的引用资料],我更倾向于使用第二个选项,但我只是仔细检查了
有什么区别 var dfd = new $.Deferred 和 var dfd = $.Deferred 在哪些情况下需要使用 new 与不使用它? 最佳答案 jQuery official doc
给定使用 Promise 构造函数的代码 let promise = () => new Promise(resolve => resolve(1)); new Promise((resolve, r
我正在研究 RxKotlin,问题出现了:defer() 和 defer{} 有什么区别 最佳答案 defer() 和 defer {} 只是写同一件事的两种方式。 Kotlin 在某些特定情况下允许
我正在尝试使用 Python 在 Google App Engine 上执行此操作: def add_to_db(person): a = PersonDb(key_name = perso
所以我有一个延迟对象数组dataCalls。 目前我正在使用以下方法来解雇所有这些,并在所有 Deferreds 解决后调用回调: $.when.apply(null, dataCalls) .
考虑以下几点: function foo(){ // Returns the jQuery deffered below. var urlToUse; $.ajax({
我刚刚看到此代码已被弃用,我一直在尝试遵循此指南:http://www.codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong/以正确的方式
我有一些元素,其中一些代码依赖于其他 中的代码元素。我看到了defer属性在这里可以派上用场,因为它允许推迟执行代码块。 为了测试它,我在 Chrome 上执行了这个:http://jsfiddle
我需要向 jQuery 的 .when() 监视的函数添加未知数量(仅在运行时已知)的 .pipe() 调用。这些调用将基于另一个异步操作的 ajax 调用。请参阅下面的代码以获得更清晰的解释: $.
我正在使用 GAE 的“deffered” ' 库 (python),它会在出现异常时自动重试任务。 有没有办法知道(在任务处理函数中)任务已尝试的次数? 我的最终目标是实现如下内容: if num_
我有几个 元素,其中一些代码依赖于其他 中的代码元素。我看到了defer属性在这里可以派上用场,因为它允许代码块在执行中被推迟。 为了测试它,我在 Chrome 上执行了这个:http://jsfi
在我看来,两者都做同样的事情。 文档: deferred.always() deferred.then() 最佳答案 看起来deferred.then()允许您传递两个单独的成功和失败回调,而 def
我正在使用 Twisted 编写代码,但在为我的扭曲互联网延迟变量想出一个合理的变量名时遇到了麻烦。这是我的候选人: d :太通用,太短,违反了 pylint 规则 C0103。 def :与内置函数
是否存在这样的情况:调用 .callback() 或 .errback() 会向调用者引发异常,而该异常不会被延迟捕获? 假设我有以下延迟和回调: from twisted.internet impo
这是代码: http://jsbin.com/lizami/edit?js,console 将代码也粘贴到此处: var aaa = $.Deferred(); var bbb = function(
这是我的尝试: deferred.defer(class1().method1, class2.method2, arg) deferred.defer(class1().method1, class
我正在尝试使用 google.appengine.ext.deferred 来运行任务。我正在将一个方法传递给 defer() 方法,该方法成功运行,但在返回时抛出一个 ValueError: F
这个问题在这里已经有了答案: What's the difference between a Deferred object and its own promise object? (3 个答案)
我下载了一个名为 jsdeferred 的库来尝试帮助我解决一些代码流问题,但我有点迷茫,因为它的示例和...“文档” 在某些事情上有点不清楚。但是当我继续阅读和挖掘,当然还有谷歌搜索阳光下的一切时,
我是一名优秀的程序员,十分优秀!