使用jQuery承诺相对于使用以前的jQuery回调函数的优点是什么?
通过使用承诺而不是直接将回调函数传递给函数,可以避免产生紧密耦合的界面,这有助于分离同步或异步代码的关注点。
承诺(Promise)是代表异步操作结果的对象,因此你可以传递它,并且这使你更加灵活。
如果使用回调函数,在调用异步操作时必须指定如何处理它,因此有了耦合。使用 Promise 可以稍后指定如何处理。
以下是一个示例:假设您想通过 AJAX 加载一些数据,同时显示一个加载页面:
void loadData = function(){
showLoadingScreen();
$.ajax("http://someurl.com", {
complete: function(data){
hideLoadingScreen();
//do something with the data
}
});
};
处理返回数据的回调函数必须调用hideLoadingScreen。
如果使用Promise,可以重写上面的片段,使其更易读,并且不必将hideLoadingScreen放在完成回调中。
var getData = function(){
showLoadingScreen();
return $.ajax("http://someurl.com").promise().always(hideLoadingScreen);
};
var loadData = function(){
var gettingData = getData();
gettingData.done(doSomethingWithTheData);
}
var doSomethingWithTheData = function(data){
//do something with data
};
更新:我已经写了一篇博客文章,提供了额外的示例,并清晰地描述了Promise是什么以及如何将其使用与使用回调进行比较。
使用 Promises 时,由于操作不需要“知道”它如何继续,只需知道何时准备好,因此与回调函数相比,耦合度更低。
当您使用回调函数时,异步操作实际上具有对其继续执行的引用,而这不是它的职责。
使用 Promises,您甚至可以在决定如何解决问题之前,轻松地对异步操作创建表达式。
因此,Promises 帮助分离链接事件和执行实际工作的关注点。
我认为承诺和回调函数的耦合程度几乎相同,没有更多或更少。
但是,承诺有其他好处:
如果你公开一个回调函数,你必须记录它是否只调用一次(像在jQuery.ajax中)还是多次(像在Array.map中)。承诺总是被调用一次。
无法在回调函数中抛出异常并使其停止执行,因此必须为错误情况提供另一个回调函数。
只能注册一个回调函数,但可以注册多个承诺,而且可以在事件之后注册它们,而且仍然会被调用。
在类型声明(TypeScript)中,使用承诺更容易阅读签名。
未来可以利用异步/ yield语法。
因为它们是标准的,所以可以制作可重用的组件。
disableScreen<T>(promiseGenerator: () => Promise<T>) : Promise<T>
{
//create transparent div
return promiseGenerator.then(val=>
{
//remove transparent div
return val;
}, error=>{
//remove transparent div
throw error;
});
}
disableScreen(()=>$.ajax(....));
更多相关内容请参见:http://www.html5rocks.com/en/tutorials/es6/promises/
编辑:
此外,虽然我仍然认为这不是主要观点,但现在我认为它们因以下原因有点松耦合:
它们是标准的(或至少尝试):使用字符串的C#或Java代码比C++中类似的代码更加松耦合,因为在C++中由于字符串的不同实现,使得它更具可重用性。拥有标准的promise后,调用者和实现彼此之间的耦合度较小,因为它们不必对自定义回调函数及其参数顺序、名称等达成一致。然而,存在许多不同版本的promise并不太有帮助。
它们促进了更基于表达式的编程,更容易组合、缓存等。
var cache: { [key: string] : Promise<any> };
function getData(key: string): Promise<any> {
return cache[key] || (cache[key] = getFromServer(key));
}
你可以认为基于表达式的编程比基于命令式/回调的编程更加松耦合,或者至少它们追求相同的目标:可组合性。
yield
你会被限制在语法 try-catch 中,而使用箭头函数时,代码行数和冗长程度保持不变。 - Esailijacb(err,result)
。如果您的所有代码都使用相同的回调约定(不像 Backbone 或一般的浏览器 API),那么是的,它与 promises 一样耦合。 - timruffs
func(arg1, arg2, callback)
更改为func(arg1, arg2, [optional]arg3, callback)
时。 - megawac