项目相关demo和代码地址
Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算.。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。 Promise 对象是一个返回值的代理,这个返回值在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。 这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回值的 promise 对象来替代原返回值。
引自 MDN
一个简单的示例 执行一个动画A,执行完之后再去执行另一个动画B
setTimeout(function(){ //A动画 console.log('A'); setTimeout(function() { //B动画 console.log('B'); },300) },300);
这里只有两个动画,如果有更多呢,就会看到一堆函数缩进
浏览器实现方式 可以在支持Promise的版本上运行
var p = new Promise(function(resolve, reject){ setTimeout(function(){ //A动画 console.log('A'); resolve(); },300); }); p.then(function(){ setTimeout(function() { //B动画 console.log('B'); },300); });
jQuery版本的实现
var deferred = $.Deferred(); setTimeout(function(){ //A动画 console.log('A'); deferred.resolve(); },300); deferred.done(function() { setTimeout(function() { //B动画 console.log('B'); },300) });
好像从代码上来看,是多了几行的样子,但是能用这种串行的方式来写,感觉一定很爽吧
Promise中有几个状态:
这里从pending状态可以切换到fulfill状态(jQuery中是resolve状态),也可以从pengding切换到reject状态,这个状态切换不可逆,且fulfilled和reject两个状态之间是不能互相切换的。
/** * simple promise * @param {[type]} fun [description] */ function PromiseB(fun) { this.succArg = undefined; this.failArg = undefined; this.succCbs = []; this.failCbs = []; this._status = this.STATUS.PENDING; this._execFun(fun); } PromiseB.prototype.STATUS = { PENDING: 1, //挂起状态 RESOLVE: 2, //完成状态 REJECT: 3 //拒绝状态 }; PromiseB.prototype._isFunction = function(f) { return Object.prototype.toString.call(f) === '[object Function]'; }; PromiseB.prototype._exec = function(callback, arg) { var newcallback; if (this._isFunction(callback)) { if (callback instanceof PromiseB) { callback.resolve(arg); } else { newcallback = new PromiseB(callback); newcallback.resolve(arg); } } }; PromiseB.prototype._execFun = function(fun) { var that = this; if (this._isFunction(fun)) { fun(function() { that.succArg = Array.prototype.slice.apply(arguments); that._status = that.STATUS.RESOLVE; that.resolve.apply(that, arguments); }, function() { that.failArg = Array.prototype.slice.apply(arguments); that._status = that.STATUS.REJECT; that.reject.apply(that, arguments); }); } else { this.resolve(fun); } }; PromiseB.prototype.resolve = function() { var arg = arguments, ret, callback = this.succCbs.shift(); if (this._status === this.STATUS.RESOLVE && callback) { ret = callback.apply(callback, arg); if (!(ret instanceof PromiseB)) { var _ret = ret; ret = new PromiseB(function(resolve) { setTimeout(function() { resolve(_ret); }); }); ret.succCbs = this.succCbs.slice(); } // this._exec(callback.apply(callback, arg), arg); } }; PromiseB.prototype.reject = function() { var arg = arguments, ret, callback = this.failCbs.shift(); if (this._status === this.STATUS.REJECT && callback) { ret = callback.apply(callback, arg); if (!(ret instanceof PromiseB)) { var _ret = ret; ret = new PromiseB(function(resolve) { setTimeout(function() { resolve(_ret); }, 200); }); ret.failCbs = this.failCbs.slice(); } } }; PromiseB.prototype.then = function(s, f) { this.done(s); this.fail(f); return this; }; PromiseB.prototype.done = function(fun) { if (this._isFunction(fun)) { if (this._status === this.STATUS.RESOLVE) { fun.apply(fun, this.succArg); } else { this.succCbs.push(fun); } } return this; }; PromiseB.prototype.fail = function(fun) { if (this._isFunction(fun)) { if (this._status === this.STATUS.REJECT) { fun.apply(fun, this.failArg); } else { this.failCbs.push(fun); } } return this; }; PromiseB.prototype.always = function(fun) { this.done(fun); this.fail(fun); return this; };