本文同步自我得博客:http://www.joeray61.com前端
不少作前端的朋友应该都据说过Promise
(或者Deferred
)对象,今天我就讲一下我对Promise
的认识web
Promise
是CommonJS
的规范之一,拥有resolve
、reject
、done
、fail
、then
等方法,可以帮助咱们控制代码的流程,避免函数的多层嵌套。现在异步在web开发中愈来愈重要,对于开发人员来讲,这种非线性执行的编程会让开发者以为难以掌控,而Promise
可让咱们更好地掌控代码的执行流程,jQuery
等流行的js库都已经实现了这个对象,年末即将发布的ES6
也将原生实现Promise
ajax
想象这样一个场景,两个异步请求,第二个须要用到第一个请求成功的数据,那么咱们代码能够这样写编程
ajax({ url: url1, success: function(data) { ajax({ url: url2, data: data, success: function() { } }); } });
若是继续下去在回调函数中进行下一步操做,嵌套的层数会愈来愈多。咱们能够进行适当的改进,把回调函数写到外面数组
function A() { ajax({ url: url1, success: function(data) { B(data); } }); } function B(data) { ajax({ url: url2, success: function(data) { ...... } }); }
即便是改写成这样,代码仍是不够直观,可是若是有了Promise对象,代码就能够写得很是清晰,一目了然,请看异步
new Promise(A).done(B);
这样函数B就不用写在A的回调中了函数
目前的ES
标准中还未支持Promise
对象,那么咱们就本身动手,丰衣足食吧。思路大体是这样的,用2个数组(doneList
和failList
)分别存储成功时的回调函数队列和失败时的回调队列this
state
: 当前执行状态,有pending
、resolved
、rejected
3种取值url
done
: 向doneList
中添加一个成功回调函数prototype
fail
: 向failList
中添加一个失败回调函数
then
: 分别向doneList
和failList
中添加回调函数
always
: 添加一个不管成功仍是失败都会调用的回调函数
resolve
: 将状态更改成resolved
,并触发绑定的全部成功的回调函数
reject
: 将状态更改成rejected
,并触发绑定的全部失败的回调函数
when
: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当全部函数都执行成功的时候执行该对象的resolve
方法,反之执行该对象的reject
方法
下面是个人具体实现过程:
var Promise = function() { this.doneList = []; this.failList = []; this.state = 'pending'; }; Promise.prototype = { constructor: 'Promise', resolve: function() { this.state = 'resolved'; var list = this.doneList; for(var i = 0, len = list.length; i < len; i++) { list[0].call(this); list.shift(); } }, reject: function() { this.state = 'rejected'; var list = this.failList; for(var i = 0, len = list.length; i < len; i++){ list[0].call(this); list.shift(); } }, done: function(func) { if(typeof func === 'function') { this.doneList.push(func); } return this; }, fail: function(func) { if(typeof func === 'function') { this.failList.push(func); } return this; }, then: function(doneFn, failFn) { this.done(doneFn).fail(failFn); return this; }, always: function(fn) { this.done(fn).fail(fn); return this; } }; function when() { var p = new Promise(); var success = true; var len = arguments.length; for(var i = 0; i < len; i++) { if(!(arguments[i] instanceof Promise)) { return false; } else { arguments[i].always(function() { if(this.state != 'resolved'){ success = false; } len--; if(len == 0) { success ? p.resolve() : p.reject(); } }); } } return p; }
目前只是实现了Promise
的基础功能,但仍然还有没法处理的状况,例如要实现3个或3个以上的异步请求的串行,目前个人Promise
没有办法支持new Promise(A).then(B).then(C)
这样的形式,jQuery
在1.7的版本中为Deferred
(Promise
)对象实现了pipe
函数,能够经过这个函数实现上述功能,代码为$.Deferred(A).pipe(B).then(C)
,我尝试去读了jQuery
这部分的代码,可是没能读懂,但愿有大神可以给一些实现思路