complete那一行那么写,是为了减少重复代码,其实就是把done和fail又调用一次,与always中的代码一样。deferred.promise( jqXHR )这句也能看出,ajax返回的是受限的Deferred对象。
jquery加了这么些个语法糖,虽然上手门槛更低了,但是却造成了一定程度的混淆。一些人虽然这么写了很久,却一直不知道其中的原理,在面试的时候只能答出一些皮毛,这是很不好的。这也是我写这篇文章的缘由。
/*!
* Promise JavaScript Library v2.0.0
*/
;
(function(window) {
var _promise = function(thens) {
this.thens = thens || [];
this.state = "";
this._CONSTANT = {
any: "any",
number: "number",
resolved: "resolved",
rejected: "rejected",
pending: "pending"
};
};
_promise.prototype = {
resolve: function() {
if(this.state == this._CONSTANT.pending) {
this.state = this._CONSTANT.resolved;
return;
}
if(this.state !== "") return;
if(this.promiseArr) {
for(var i = 0, j = this.promiseArr.length; i < j; i++) {
this.promiseArr[i].resolveCount++;
}
if(this.promiseArr[0].action !== this._CONSTANT.any) {
if(this.resolveCount !== this.promiseArr.length) {
return;
}
} else {
if(this.resolveCount > 1) {
return;
}
}
}
this.state = this._CONSTANT.resolved;
if(!this.thens) return;
if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
var t, n;
while(t = this.thens.shift()) {
if(typeof t === this._CONSTANT.number) {
var self = this;
setTimeout(function() {
var prms = new _promise(self.thens);
prms.resolve();
}, t);
break;
}
var doneFn = t.done,
action = t.action;
if(!doneFn) continue;
if(doneFn instanceof Array) {
var arr = [];
for(var i = 0, j = doneFn.length; i < j; i++) {
var df = doneFn[i];
if(df instanceof _promise) {
df.thens = this.thens;
arr.push(df);
} else {
var m = df.apply(null, arguments);
if(m instanceof _promise) {
m.thens = this.thens;
arr.push(m);
}
}
}
var l = arr.length;
if(l === 0) {
continue;
} else {
for(var i = 0; i < l; i++) {
arr[i].promiseArr = arr;
arr[i].action = action;
arr[i].resolveCount = 0;
}
break;
}
} else {
if(doneFn instanceof _promise) {
doneFn.thens = this.thens;
break;
} else {
n = doneFn.apply(null, arguments);
if(n instanceof _promise) {
n.thens = this.thens;
break;
}
}
continue;
}
}
},
reject: function() {
if(this.state !== "") return;
if(this.promiseArr && this.promiseArr[0].action === this._CONSTANT.any) {
if(this.promiseArr[this.promiseArr.length - 1] !== this) {
return;
}
}
this.state = this._CONSTANT.rejected;
if(!this.thens) return;
if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
var t, n;
while(t = this.thens.shift()) {
if(typeof t === this._CONSTANT.number) {
var self = this;
setTimeout(function() {
var prms = new _promise(self.thens);
prms.resolve();
}, t);
break;
}
if(t.fail) {
n = t.fail.apply(null, arguments);
if(n instanceof _promise) {
n.thens = this.thens;
break;
}
continue;
}
break;
}
},
notify: function() {
var t = this.thens[0];
t.progress.apply(null, arguments);
},
then: function(done, fail, progress) {
this.thens.push({
done: done,
fail: fail,
progress: progress
});
return this;
},
any: function(done, fail, progress) {
this.thens.push({
done: done,
fail: fail,
progress: progress,
action: this._CONSTANT.any
});
return this;
},
done: function(done) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].done) {
this.thens.push({
done: done
});
} else {
this.thens[this.thens.length - 1].done = done;
}
return this;
},
fail: function(fail) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].fail) {
this.thens.push({
fail: fail
});
} else {
this.thens[this.thens.length - 1].fail = fail;
}
return this;
},
progress: function(progress) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].progress) {
this.thens.push({
progress: progress
});
} else {
this.thens[this.thens.length - 1].progress = progress;
}
return this;
},
ensure: function(finallyCB) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].finallyCB) {
this.thens.push({
finallyCB: finallyCB
});
} else {
this.thens[this.thens.length - 1].finallyCB = finallyCB;
}
return this;
},
always: function(alwaysCB, progress) {
this.thens.push({
done: alwaysCB,
fail: alwaysCB,
progress: progress
});
return this;
},
wait: function(ms) {
this.thens.push(~~ms);
return this;
}
}
var Promise = function(parameter) {
var prms = new _promise();
if(parameter) {
if(arguments.length > 1) {
prms.thens[0] = {};
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
} else {
prms = parameter();
if(prms instanceof _promise) return prms;
}
}
return prms;
};
Promise.when = function() {
var prms = new _promise();
prms.thens[0] = {};
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
return prms;
};
Promise.any = function() {
var prms = new _promise();
prms.thens[0] = {};
prms.thens[0].action = prms._CONSTANT.any;
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
return prms;
};
Promise.timeout = function(promise, ms) {
setTimeout(function() {
promise.reject();
}, ms);
return promise;
}
Promise.gtTime = function(promise, ms) {
promise.state = promise._CONSTANT.pending;
setTimeout(function() {
if(promise.state == promise._CONSTANT.resolved) {
promise.state = "";
promise.resolve();
}
promise.state = "";
}, ms);
return promise;
}
if(typeof module === "object" && module && typeof module.exports === "object") {
module.exports = Promise;
} else {
window.Promise = Promise;
if(typeof define === "function" && define.amd) {
define("promise", [], function() {
return Promise;
});
}
}
}(window));
promise.js提供了done和resolve方法,done负责注册成功的回调函数,resolve负责触发。
function cb() {
alert('success')
}
var prms = Promise()
prms.done(cb)
setTimeout(function() {
prms.resolve()
}, 3000)
在3秒之后,浏览器将alert “success”。
当然你也可以通过prms.resolve(“xxx”)传递参数给cb函数使用,如:
function cb(num) {
alert(num)
}
var prms = Promise()
prms.done(cb)
setTimeout(function() {
prms.resolve(1)
}, 3000)
在3秒之后,浏览器将alert “1”。
fail/reject
fail函数负责注册失败的回调函数,reject负责触发。如:
function cb() {
alert('fail')
}
var prms = Promise()
prms.fail(cb)
setTimeout(function () {
prms.reject()
}, 3000)
progress/notify
progress函数负责注册处理中进度的回调函数,notify负责触法。如:
function cb() {
alert('progress')
}
var prms = Promise()
prms.progress(cb)
setInterval(function() {
prms.notify()
}, 2000)
每隔两秒浏览器会弹出一个progress。
chain
function cb1() {
alert('success')
}
function cb2() {
alert('fail')
}
function cb3() {
alert('progress')
}
var prms = Promise();
prms.done(cb1).fail(cb2).progress(cb3)
setTimeout(function () {
prms.resolve()
//prms.reject()
//prms.notify()
}, 3000)
then
function fn1() {
alert('success')
}
function fn2() {
alert('fail')
}
function fn3() {
alert('progress')
}
var prms = Promise()
prms.then(fn1, fn2, fn3)
prms.resolve()
prms.reject()
prms.notify()
当然也支持prms.then().then().then()……….
当then的第一个参数为一个数组的时候,要等所有task都完成:
f1().then([f2_1, f2_2]).then(f3)
如上面的代码:
f1执行完后,同时执行f2_1和f2_2,当f2_1和f2_2全部都执行完成才会执行f3。
any
f1().any([f2_1, f2_2]).then(f3)
f1执行完后,同时执行f2_1和f2_2,当f2_1和f2_2中的任意一个执行完成才会执行f3。
always
var prms = Promise()
prms.always(function () {
alert(2)
})
setTimeout(function () {
// prms.resolve()
prms.reject()
}, 3000)
always(fn)等同于then(fn,fn),也等同于done(fn).fail(fn)
wait
function f10() {
var promise = Promise();
setTimeout(function () {
console.log(10);
promise.resolve();
}, 4500)
return promise;
}
function f11() {
var promise = Promise();
setTimeout(function () {
console.log(11);
promise.resolve();
}, 1500)
return promise;
}
f11().wait(5000).then(f10) //execute f11 then wait 5000ms then execute f10
ensure
ensure方法类似try…catch..finally中的finally,不管task成功失败都会执行。
Promise.when
Promise.when(f1(), f2()).then(f3).then(f4)
function f1() {
var promise = Promise();
setTimeout(function () {
console.log(1);
promise.resolve("from f1");
}, 1500)
return promise;
}
function f2() {
var promise = Promise();
setTimeout(function () {
console.log(2);
promise.resolve();
}, 5500)
return promise;
}
function f3() {
var promise = Promise();
setTimeout(function () {
console.log(3);
promise.resolve();
}, 1500)
return promise;
}
function f4() {
var promise = Promise();
setTimeout(function () {
console.log(4);
promise.resolve();
}, 1500)
return promise;
}
上面promise.when的等同简略写法也可以是:Promise(f1(),f2()).then….
Promise.any
Promise.any的使用和when一样,when的意义是等所有task都完成再执行后面的task,而any的意义是任何一个task完成就开始执行后面的task。
Promise.timeout
Promise.timeout(f1(), 2000).then(f2, function () {
alert("timeout");
}).wait(5000).then(f3);
function f1() {
var promise = Promise();
setTimeout(function () {
console.log(1);
promise.resolve("from f1");
}, 1500)
return promise;
}
function f2() {
var promise = Promise();
setTimeout(function () {
console.log(2);
promise.resolve();
}, 1500)
return promise;
}
function f3() {
var promise = Promise();
setTimeout(function () {
console.log(3);
promise.resolve();
}, 1500)
return promise;
}
with wind.js
That’s all.Have Fun!