大多情况下,promise作为一个模型,提供了一个在软件工程中描述延时(或将来)概念的解决方案。它背后的思想我们已经介绍过:
不是执行一个方法,然后阻塞应用程序等待结果返回,而是返回一个promise对象来满足未来值。
这样看来,Promise/A只是一种规范,Deferred可以看作这种规范的具体实现,旨在提供通用的接口,用来简化异步编程难度,说白了就是:
一个可链式操作的对象,提供多个回调函数的注册,以及回调列队的回调,并转达任何异步操作成功或失败的消息。
jQuery.Deferred()背后的设计理念来自 CommonJS Promises/A , jQuery.Deferred()基于这个理念实现,但并没有完全遵循其设计, 它代表了一种可能会长时间运行而且不一定必须完整的操作的结果,简单的描述下规范中定义的“Promise”。
promise模式在任何时刻都处于以下三种状态之一:
未完成(unfulfilled) 已完成(resolved) 拒绝(rejected)
CommonJS Promise/A 标准这样定义的,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,这样可以形成“管道”风格。
看看jQuery的Deferred源码中对动作接口的定义:
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
Deferred中定义的动作是非常多的,抽象的看其实可以类似一种观察者模式的实现。
观察者模式中的订阅方法:
Done (操作完成) Fail (操作失败) Progress (操作进行中
观察中模式中的发布方法:
resolve(解决) reject(拒绝) notify(通知)
而且还提供了可以定义运行时的this对象的fire,fireWith,所以扩展了3个可以定义上下文的的接口:
resolveWith rejectWith notifyWith
所以按照这样的规范,我们的使用就应该是这样:见右边代码。
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<title></title>
</head>
<body>
<button id="aaron1">例一:基本用法</button>
<button id="aaron2">例二:过滤器</button>
<button id="aaron3">例三:promise方法</button>
<script type="text/javascript">
//例一
$("#aaron1").on("click", function() {
// 构建一个deferred对象
var dtd = $.Deferred();
// 给deferred注册一个成功后的回调通知
dtd.done(function() {
show('成功')
})
// 开始执行一段代码
setTimeout(function() {
dtd.resolve(); // 改变deferred对象的执行状态
}, 2000);
})
//例二:过滤器
var filterResolve = function() {
var defer = $.Deferred(),
filtered = defer.then(function(value) {
return value * 2;
});
defer.resolve(5);
filtered.done(function(value) {
show("Value is ( 2*5 = ) 10: " + value);
});
};
$("#aaron2").on("click", filterResolve)
//例三:实现promise方法
$("#aaron3").on("click", function() {
var obj = {
hello: function(name) {
show("你好 " + name);
}
},
defer = $.Deferred();
// 设置一个promise
defer.promise(obj);
//解决一个deferred
defer.resolve("慕课网");
obj.done(function(name) {
obj.hello(name);
}).hello("Aaron");
})
function show(data) {
$("body").append('<li>' + data + '</li>')
}
</script>
</body>
</html>