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
})()