异步 JavaScript - 回调与延迟/承诺 [重复]
Posted
技术标签:
【中文标题】异步 JavaScript - 回调与延迟/承诺 [重复]【英文标题】:Asynchronous JavaScript - Callbacks vs Deferred/Promise [duplicate] 【发布时间】:2012-12-17 03:41:33 【问题描述】:可能重复:What are the differences between Deferred, Promise and Future in javascript?
最近我一直在努力提高我的 JavaScript 应用程序的质量。
我采用的一种模式是使用单独的“数据上下文”对象为我的应用程序加载数据(以前我直接在我的视图模型中执行此操作)。
以下示例返回在客户端初始化的数据:
var mockData = (function($, undefined)
var fruit = [
"apple",
"orange",
"banana",
"pear"
];
var getFruit = function()
return fruit;
;
return
getFruit: getFruit
)(jQuery);
在大多数情况下,我们将从服务器加载数据,因此我们无法立即返回响应。对于我们如何在 API 中处理这个问题,我似乎有两种选择:
-
使用回调
返回promise。
以前我一直使用回调方法:
var getFruit = function(onFruitReady)
onFruitReady(fruit);
;
// ...
var FruitModel = function(dataContext, $)
return
render: function()
dataContext.getFruit(function(fruit)
// do something with fruit
);
;
;
但是,我可以看到最终可能会陷入回调地狱,尤其是在构建复杂的 JavaScript 应用程序时。
然后我遇到了 Promises 设计模式。我没有要求调用者提供回调,而是返回一个可以观察到的“承诺”:
var getFruit = function()
return $.Deferred().resolve(fruit).promise();
;
// ...
dataContext.getFruit().then(function(fruit)
// do something with fruit
);
我可以看到使用这种模式的明显好处,特别是因为我可以wait
处理多个延迟对象,这在为单页应用程序加载初始化数据时非常有用。
但是,在我开始愤怒地使用每种模式之前,我很想了解每种模式的优缺点。我也对这是否是其他库的发展方向感兴趣。jQuery 似乎就是这种情况。
这是我用于测试的小提琴的link。
【问题讨论】:
好消息:jQuery ajax API已经返回 Promises! Read up on the mechanism here. 是的,当我在寻找一种方法来抽象我的 ajax 调用时,这就是我最初遇到这种模式的原因。 我认为回调会快一点,但我真的很喜欢你的问题,并且对答案很感兴趣! 啊。好吧,我的意思是您实际上不需要添加太多;这些调用的返回值可以立即使用,因此只需摆脱传递“成功”回调的习惯并进入调用.done()
等的习惯。
【参考方案1】:
Promise 也依赖于幕后的回调,所以这并不是真正的一对一。
回调的好处是它们很容易用纯 JavaScript 实现(例如在 ajax 调用中)。
Promises 需要一个额外的抽象层,这通常意味着您将依赖一个库(在您的情况下这不是问题,因为您已经在使用 jQuery)。当您并行处理多个异步调用时,它们是完美的。
【讨论】:
请注意,自 2014 年 3 月起,浏览器已开始实现原生承诺,因此我的声明仅适用于 polyfill。【参考方案2】:从阅读@Pointy 链接到的jQuery docs 来看,听起来不同之处在于延迟 API 允许您指定在请求完成时要调用的多个函数:
从 jQuery 1.5 开始,错误(失败)、成功(完成)和完成(始终,从 jQuery 1.6 开始)回调挂钩是先进先出的托管队列。这意味着您可以为每个挂钩分配多个回调。请参阅延迟对象方法,这些方法在内部为这些 $.ajax() 回调挂钩实现。
另见:deferred.then()
【讨论】:
Deferreds/promises允许您指定多个要调用的函数,尽管他们这样做更容易。特殊功能是 (a) 可以在代码中的任何位置添加函数(例如.done()
或 .fail()
),前提是 Deferred/promise 在范围内,以及 (b) 在 Deferred 之后添加函数解决/拒绝将立即触发。通过公开其内部 .Callbacks()
实用程序,jQuery 使这种类型的功能成为可能,而无需使用 Deferreds/promises,但它们消除了编码/调试的痛苦。以上是关于异步 JavaScript - 回调与延迟/承诺 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
Twisted的延迟是否与JavaScript中的Promise相同?