Promise標(biāo)準(zhǔn)
-
Promise規(guī)范有很多,如Promise/A,Promise/B,Promise/D以及Promise/A的升級(jí)版Promise/A+。ES6中采用了Promise/A+規(guī)范。
英文版規(guī)范: Promises/A+規(guī)范
中文版規(guī)范: Promises/A+規(guī)范(中文) -
Promise標(biāo)準(zhǔn)解讀
(1) 一個(gè)promise的當(dāng)前狀態(tài)只能是pending、fulfilled和rejected三種之一。狀態(tài)改變只能是pending到fulfilled或者pending到rejected。狀態(tài)改變不可逆。
(2)promise的then方法接收兩個(gè)可選參數(shù),表示該promise狀態(tài)改變時(shí)的回調(diào)(promise.then(onFulfilled, onRejected))。then方法返回一個(gè)promise。then方法可以被同一個(gè)promise調(diào)用多次。
實(shí)現(xiàn)Promise
Promise標(biāo)準(zhǔn)僅描述了then方法的行為,未對(duì)catch、all、race方法進(jìn)行描述,也未規(guī)范如何創(chuàng)建一個(gè)Promise對(duì)象。ES6中Promise提供了以下API。
(1) 構(gòu)造函數(shù)
function Promise(resolver) {}
(2) 原型方法
Promise.prototype.then = function() {}
Promise.prototype.catch = function() {}
(3) 靜態(tài)方法
Promise.resolve = function() {}
Promise.reject = function() {}
Promise.all = function() {}
Promise.race = function() {}
構(gòu)造函數(shù)
-
Promise/A+標(biāo)準(zhǔn)并沒有指定如何構(gòu)造一個(gè)Promise對(duì)象,我們以ES6原生Promise模塊里通過構(gòu)造函數(shù)創(chuàng)建Promise對(duì)象的方式實(shí)現(xiàn)Promise構(gòu)造函數(shù)。ES6中通過構(gòu)造函數(shù)創(chuàng)建Promise對(duì)象的簡(jiǎn)單用法如下:
const promise = new Promise((resolve) => {
setTimeout(()=> {
resolve(1);
}, 2000);
});
promise.then(a=> alert(a));
promise.then(a => alert(a+1));
構(gòu)造函數(shù)用法總結(jié):
(1) 構(gòu)造函數(shù)接收一個(gè)executor立即執(zhí)行函數(shù)
(2) executor立即執(zhí)行函數(shù)接收一個(gè)resolve函數(shù)
(3) promise對(duì)象的then方法綁定狀態(tài)變?yōu)?code>fulfilled時(shí)的回調(diào)
(4) resolve函數(shù)被調(diào)用時(shí)會(huì)觸發(fā)then方法中的回調(diào)
- 構(gòu)造函數(shù)的簡(jiǎn)單實(shí)現(xiàn)
function Promise(executor) {
var self = this;
self.status = 'pending'; //promise當(dāng)前的狀態(tài)
self.data = undefined; //promise的值
self.onResolvedCallback = [];
//promise狀態(tài)變?yōu)閞esolve時(shí)的回調(diào)函數(shù)集,可能有多個(gè)
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
for(var i = 0; i < self.onResolvedCallback.length; i++) {
self.onResolvedCallback[i](value);
}
}
}
executor(resolve);
};
Promise.prototype.then = function (resolve) {
this.onResolvedCallback.push(resolve);
};
-
executor自執(zhí)行函數(shù)接收的第二個(gè)參數(shù)為reject函數(shù)且reject函數(shù)在promise對(duì)象狀態(tài)變?yōu)?code>rejected時(shí)或executor拋出異常時(shí)觸發(fā)。
function Promise(executor) {
var self = this;
self.status = 'pending'; //promise當(dāng)前的狀態(tài)
self.data = undefined; //promise的值
self.onResolvedCallback = [];
//promise狀態(tài)變?yōu)閞esolve時(shí)的回調(diào)函數(shù)集,可能有多個(gè)
self.onRejectedCallback = [];
//promise狀態(tài)變?yōu)閞eject時(shí)的回調(diào)函數(shù)集,可能有多個(gè)
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
for(var i = 0; i < self.onResolvedCallback.length; i++) {
self.onResolvedCallback[i](value);
}
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.data = reason;
for(var i = 0; i < self.onRejectedCallback.length; i++) {
self.onRejectedCallback[i](reason);
}
}
}
try {
executor(resolve, reject);
} catch (e){
reject(e);
}
};
Promise.prototype.then = function (onResolve, onReject) {
this.onResolvedCallback.push(onResolve);
this.onRejectedCallback.push(onReject);
};
總結(jié):①executor函數(shù)作為實(shí)參在創(chuàng)建Promise對(duì)象時(shí)傳入Promise構(gòu)造函數(shù)。②resolve和reject函數(shù)作為實(shí)參傳入executor函數(shù)。③value作為實(shí)參傳入resolve和reject函數(shù)。
- 如果
executor自執(zhí)行函數(shù)中的resolve函數(shù)立即觸發(fā)時(shí),發(fā)現(xiàn)Promise失效,例如:
const promise = new Promise((resolve) => {
resolve(1);
});
promise.then((a) => alert(a));
解決辦法:需要將promise的resolve和reject異步執(zhí)行。
function resolve(value) {
setTimeout(function () {
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
for(var i = 0; i < self.onResolvedCallback.length; i++) {
self.onResolvedCallback[i](value);
}
}
})
}
function reject(reason) {
setTimeout(function () {
if(self.status === 'pending') {
self.status = 'rejected';
self.data = reason;
for(var i = 0; i < self.onRejectedCallback.length; i++) {
self.onRejectedCallback[i](reason);
}
}
})
}
then方法
- 在構(gòu)造函數(shù)中的示例中,
then方法并沒有返回一個(gè)promise對(duì)象,而Promise/A+規(guī)范中規(guī)定then方法用來注冊(cè)promise對(duì)象狀態(tài)改變時(shí)的回調(diào),且返回一個(gè)新的promise對(duì)象。
(1)then方法返回一個(gè)新的promise對(duì)象。
(2)executor自執(zhí)行函數(shù)中的resolve參數(shù)調(diào)用時(shí)執(zhí)行then方法的第一個(gè)回調(diào)函數(shù)onResolved。
(3)executor自執(zhí)行函數(shù)中的reject參數(shù)調(diào)用時(shí)執(zhí)行then方法的第二個(gè)回調(diào)函數(shù)onRejected。
Promise.prototype.then = function (onResolved, onRejected) {
var self = this;
var promise2;
onResolved = typeof onResolved === 'function'
? onResolved
: function (value) {return value};
onRejected = typeof onRejected === 'function'
? onRejected
: function (reason) {throw reason};
//promise對(duì)象當(dāng)前狀態(tài)為resolved
if(self.status === 'resolved') {
return promise2 = new Promise(function (resolve, reject) {
try {
//調(diào)用onResolve回調(diào)函數(shù)
var x = onResolved(self.data);
//如果onResolve回調(diào)函數(shù)返回值為一個(gè)promise對(duì)象
if(x instanceof Promise) {
//將它的結(jié)果作為promise2的結(jié)果
x.then(resolve, reject);
} else {
resolve(x);//執(zhí)行promise2的onResolve回調(diào)
}
} catch (e) {
reject(e); //執(zhí)行promise2的onReject回調(diào)
}
})
}
//promise對(duì)象當(dāng)前狀態(tài)為rejected
if(self.status === 'rejected') {
return promise2 = new Promise(function (resolve, reject) {
try {
var x = onRejected(self.data);
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (e) {
reject(e)
}
})
}
//promise對(duì)象當(dāng)前狀態(tài)為pending
//此時(shí)并不能確定調(diào)用onResolved還是onRejected,需要等當(dāng)前Promise狀態(tài)確定。
//所以需要將callBack放入promise1的回調(diào)數(shù)組中
if(self.status === 'pending') {
return promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallback.push(function (value) {
try {
var x = onResolved(self.data);
if (x instanceof Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
} catch (e) {
reject(e);
}
})
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(self.data);
if (x instanceof Promise) {
x.then(resolve, reject)
} else {
resolve(x);
}
} catch (e) {
reject(e)
}
})
})
}
};
- 參照
Promise/A+標(biāo)準(zhǔn)對(duì)promise進(jìn)行改寫
function resolvePromise(promise2, x, resolve, reject) {
var then
var thenCalledOrThrow = false
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise!'))
}
if (x instanceof Promise) {
if (x.status === 'pending') { //because x could resolved by a Promise Object
x.then(function(v) {
resolvePromise(promise2, v, resolve, reject)
}, reject)
} else { //but if it is resolved, it will never resolved by a Promise Object but a static value;
x.then(resolve, reject)
}
return
}
if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
then = x.then //because x.then could be a getter
if (typeof then === 'function') {
then.call(x, function rs(y) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return resolvePromise(promise2, y, resolve, reject)
}, function rj(r) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(e)
}
} else {
resolve(x)
}
}
Promise.prototype.then = function(onResolved, onRejected) {
var self = this
var promise2
onResolved = typeof onResolved === 'function' ? onResolved : function(v) {
return v
}
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {
throw r
}
if (self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 異步執(zhí)行onResolved
try {
var x = onResolved(self.data)
resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
})
}
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 異步執(zhí)行onRejected
try {
var x = onRejected(self.data)
resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
})
}
if (self.status === 'pending') {
// 這里之所以沒有異步執(zhí)行,是因?yàn)檫@些函數(shù)必然會(huì)被resolve或reject調(diào)用,而resolve或reject函數(shù)里的內(nèi)容已是異步執(zhí)行,構(gòu)造函數(shù)里的定義
return promise2 = new Promise(function(resolve, reject) {
self.onResolvedCallback.push(function(value) {
try {
var x = onResolved(value)
resolvePromise(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(reason)
resolvePromise(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
})
}
}
完整代碼
var Promise = (function() {
function Promise(resolver) {
if (typeof resolver !== 'function') { //resolver必須是函數(shù)
throw new TypeError('Promise resolver ' + resolver + ' is not a function')
}
if (!(this instanceof Promise)) return new Promise(resolver)
var self = this //保存this
self.callbacks = [] //保存onResolve和onReject函數(shù)集合
self.status = 'pending' //當(dāng)前狀態(tài)
function resolve(value) {
setTimeout(function() { //異步調(diào)用
if (self.status !== 'pending') {
return
}
self.status = 'resolved' //修改狀態(tài)
self.data = value
for (var i = 0; i < self.callbacks.length; i++) {
self.callbacks[i].onResolved(value)
}
})
}
function reject(reason) {
setTimeout(function(){ //異步調(diào)用
if (self.status !== 'pending') {
return
}
self.status = 'rejected' //修改狀態(tài)
self.data = reason
for (var i = 0; i < self.callbacks.length; i++) {
self.callbacks[i].onRejected(reason)
}
})
}
try{
resolver(resolve, reject) //執(zhí)行resolver函數(shù)
} catch(e) {
reject(e)
}
}
function resolvePromise(promise, x, resolve, reject) {
var then
var thenCalledOrThrow = false
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise!'))
}
if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
then = x.then
if (typeof then === 'function') {
then.call(x, function rs(y) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return resolvePromise(promise, y, resolve, reject)
}, function rj(r) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(r)
})
} else {
return resolve(x)
}
} catch(e) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(e)
}
} else {
return resolve(x)
}
}
Promise.prototype.then = function(onResolved, onRejected) {
//健壯性處理,處理點(diǎn)擊穿透
onResolved = typeof onResolved === 'function' ? onResolved : function(v){return v}
onRejected = typeof onRejected === 'function' ? onRejected : function(r){throw r}
var self = this
var promise2
//promise狀態(tài)為resolved
if (self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() {
try {
//調(diào)用then方法的onResolved回調(diào)
var x = onResolved(self.data)
//根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
//promise2狀態(tài)變?yōu)閞ejected
return reject(e)
}
})
})
}
//promise狀態(tài)為rejected
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() {
try {
//調(diào)用then方法的onReject回調(diào)
var x = onRejected(self.data)
//根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
//promise2狀態(tài)變?yōu)閞ejected
return reject(e)
}
})
})
}
//promise狀態(tài)為pending
//需要等待promise的狀態(tài)改變
if (self.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
self.callbacks.push({
onResolved: function(value) {
try {
//調(diào)用then方法的onResolved回調(diào)
var x = onResolved(value)
//根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
//promise2狀態(tài)變?yōu)閞ejected
return reject(e)
}
},
onRejected: function(reason) {
try {
//調(diào)用then方法的onResolved回調(diào)
var x = onRejected(reason)
//根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
//promise2狀態(tài)變?yōu)閞ejected
return reject(e)
}
}
})
})
}
}
//獲取當(dāng)前Promise傳遞的值
Promise.prototype.valueOf = function() {
return this.data
}
//由then方法實(shí)現(xiàn)catch方法
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected)
}
//finally方法
Promise.prototype.finally = function(fn) {
return this.then(function(v){
setTimeout(fn)
return v
}, function(r){
setTimeout(fn)
throw r
})
}
Promise.prototype.spread = function(fn, onRejected) {
return this.then(function(values) {
return fn.apply(null, values)
}, onRejected)
}
Promise.prototype.inject = function(fn, onRejected) {
return this.then(function(v) {
return fn.apply(null, fn.toString().match(/\((.*?)\)/)[1].split(',').map(function(key){
return v[key];
}))
}, onRejected)
}
Promise.prototype.delay = function(duration) {
return this.then(function(value) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(value)
}, duration)
})
}, function(reason) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(reason)
}, duration)
})
})
}
Promise.all = function(promises) {
return new Promise(function(resolve, reject) {
var resolvedCounter = 0
var promiseNum = promises.length
var resolvedValues = new Array(promiseNum)
for (var i = 0; i < promiseNum; i++) {
(function(i) {
Promise.resolve(promises[i]).then(function(value) {
resolvedCounter++
resolvedValues[i] = value
if (resolvedCounter == promiseNum) {
return resolve(resolvedValues)
}
}, function(reason) {
return reject(reason)
})
})(i)
}
})
}
Promise.race = function(promises) {
return new Promise(function(resolve, reject) {
for (var i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function(value) {
return resolve(value)
}, function(reason) {
return reject(reason)
})
}
})
}
Promise.resolve = function(value) {
var promise = new Promise(function(resolve, reject) {
resolvePromise(promise, value, resolve, reject)
})
return promise
}
Promise.reject = function(reason) {
return new Promise(function(resolve, reject) {
reject(reason)
})
}
Promise.fcall = function(fn){
// 雖然fn可以接收到上一層then里傳來的參數(shù),但是其實(shí)是undefined,所以跟沒有是一樣的,因?yàn)閞esolve沒參數(shù)啊
return Promise.resolve().then(fn)
}
Promise.done = Promise.stop = function(){
return new Promise(function(){})
}
Promise.deferred = Promise.defer = function() {
var dfd = {}
dfd.promise = new Promise(function(resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
try { // CommonJS compliance
module.exports = Promise
} catch(e) {}
return Promise
})()