Promises是一种异步编程模型,通过一组API来规范化异步操作,这样也能够让异步操作的流程控制更加容易。
下面的代码是假设执行一个异步队列,每一项都会使用上一项返回的数据:
function nest(url, params, fn) { $.getJSON(url, params, function(data) { console.log(data); fn.call(this); }); }
nest('promise.php', {a:1}, function(data1) { nest('promise.php', {b:2}, function(data2) { nest('promise.php', {c:3}, function(data3) { console.log('同步完成'); }); }); });
这是一个回调金字塔,当异步的任务很多的时候,需要维护大量的callback。这嵌套的自己眼睛都看不清了吧。
Promise/A+规范就是为了解决上面的问题,可以用类似下面的代码来改进,“nest”也会做些修改:
promise.then(nest('promise.php', {a:1})) .then(nest('promise.php', {b:2})) .then(nest('promise.php', {c:3}));
下图是改进的图片示例,我在画图的时候也感觉到,左边的比较难画,右边的很好画。
接下来会围绕改进金字塔,实现规范展开。
一、Promises/A+规范说明
1)一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
2)一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
3)promise必须实现then方法,而且then必须返回一个promise
4)同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
5)then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用
6)另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。
7)then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
接下来先实现一个简易的,只有完成状态,没有拒绝和等待状态。
二、简单实现
Promise对象的实现:
function Promise(fn) { this._status = 'pending'; this._resolves = []; //队列 this._fn = fn; return this; } Promise.prototype = { then: function(resolve) { var next = this._next || (this._next = new Promise()); //下一个promise对象 this._resolves.push(resolve); //设置队列 return next; }, resolved: function(value) { //改变状态 this._status = 'fulfilled'; this._result = (this._fn && this._fn(value)) || value; while (fn = this._resolves.shift()) { //循环调用队列 this._fire(this._next, fn); } }, _fire: function(nextPromise, nextFn) { var nextResult = nextFn(this._result); if (nextResult instanceof Promise) { //判断回调是否是Promise对象 //只有当nextResult的状态为fulfilled,下一个promise才可以执行 nextResult.then(function(value) { nextPromise.resolved(value); }); } else { nextPromise.resolved(nextResult); } } };
演示用的函数:
function nest2(url, params) { return function(pre) { var promise = new Promise(); $.getJSON(url, params, function(data) { promise.resolved(data); }); return promise; }; } function begin(value) { return value + '!'; }
初始化代码:
var promise = new Promise(begin); promise.then(nest2('promise.php', {a: 1})) .then(nest2('promise.php', {b: 2})); promise.resolved('开始');
也可以另外一种方式调用,这样的话内部的_resloves队列中会有多个值
var promise = new Promise(begin);
promise.then(nest2('promise.php', {a: 1})) promise.then(nest2('promise.php', {b: 2})); promise.resolved('开始');
demo下载:
http://download.csdn.net/detail/loneleaf1/9391315
参考资料:
http://www.alloyteam.com/2014/05/javascript-promise-mode/ JavaScript Promise启示录
http://www.cnblogs.com/fsjohnhuang/p/4135149.html JS魔法堂:剖析源码理解Promises/A规范
http://www.cnblogs.com/aaronjs/archive/2012/11/17/2774440.html 使用Promises/A
http://rapheal.sinaapp.com/2013/01/26/jquery-src-deferred/ $.Deferred
http://www.ituring.com.cn/article/66566 Promises/A+规范