大多情况下,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>