Promise
(function (window) {
/**
* 将经常使用的字符串定义为常量
*/
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
/**
* MyPromise 构造函数
* 1. Promise 是一个类,在执行这个类的时候会传入一个执行器函数(excutor),这个执行器会立即执行(同步执行)
* 2. Promise 会有三种状态
* -Pending 等待
* -Fulfilled 完成
* -Rejected 失败
*
* 3. 状态只能由 Pending --> Fulfilled 或者 Pending --> Rejected,且一但发生改变便不可二次修改;
* 4. Promise 中使用 resolve 和 reject 两个函数来更改状态;
* 5. then 方法内部做但事情就是状态判断
* -如果状态是成功,调用成功回调函数
* -如果状态是失败,调用失败回调函数
*
* @constructor
*/
function MyPromise(excutor) {
// 将当前promise对象保存起来
const that = this;
// 给promise对象指定一个状态,初始值为pending
that.status = PENDING;
// 给promise对象指定一个用于存储结果数据的属性
that.data = undefined;
// 给promise对象添加回调函数,每个元素结构:{onResolved() {}, onRejected() {}}
that.callbacks = [];
/**
* 1. 如果反复调用reason,后面的不执行,因为promise状态只改变一次
* 2. 将状态改为resolved
* 3. 保存value数据
* 4. 如果有待执行的callback函数,立即【异步】执行回调(添加到异步队列中)
* 不一定有回调函数,因为可能先指定,可能后指定
* @param value
*/
function resolve(value){
// 1. 如果反复调用reason,后面的不执行,因为promise状态只改变一次
if (that.status !== PENDING){
return;
}
// 2. 将状态改为resolved
that.status = RESOLVED;
// 3. 保存value数据
that.data = value;
// 4. 如果有待执行的callback函数,立即【异步】执行成功的回调(添加到异步队列中,这里使用setTimeout)
if (that.callbacks.length > 0){
// 遍历,【异步执行】所有成功的回调函数
that.callbacks.forEach(callbackObj => {
setTimeout(() => {
callbackObj.onResolved(value);
},0)
})
}
}
function reject(reason){
// 1. 如果反复调用reason,后面的不执行,因为promise状态只改变一次
if (that.status !== PENDING){
return;
}
// 2. 将状态改为resolved
that.status = REJECTED;
// 3. 保存value数据
that.data = reason;
// 4. 如果有待执行的callback函数,立即【异步】执行失败的回调(添加到异步队列中,这里使用setTimeout)
if (that.callbacks.length > 0){
// 遍历,异步执行所有成功的回调函数
that.callbacks.forEach(callbackObj => {
setTimeout(() => {
callbackObj.onRejected(reason);
},0)
})
}
}
/**
* 立即执行exctuor,传两个用于改变promise状态的函数(需要内部提前定义好,由外部调用)
* 执行器中可能:
* . 调resolve -> promise成功
* . 调reject -> promise失败
* . 抛异常 -> promise失败
*/
try {
excutor(resolve, reject)
}catch (error) {
reject(error)
}
}
/**
* Promise 原型对象的 then(), 指定成功和失败的回调函数(可以提前指定 或 之后指定)
*
* then()函数:
* 1. 返回一个新的promise对象
* 【new MyPromise】
*
* 2. 判断当前promise状态
* 【that.status】
* 1). 当前promise状态是pending,将成功和失败的回调函数保存callbacks容器中缓存
* 2). 如果promise当前是resolve状态,异步执行onResolve并改变return的promise状态
* 3). 如果promise当前是reject状态,异步执行onRejected并改变return的promise状态
*
* 3. 返回的promise的结果由回调函数 onResolved/onRejected 【异步】执行的结果决定
* 【handle() - result】
* 1). 如果抛出异常, return的promise就会失败, reason为error
* 2). 如果回调函数返回的不是promise, return的promise就会成功, value就是返回的值
* 3). 如果回调函数返回的是promise, return的promise结果就是这个promise的结果
*
* 4. 指定回调函数默认值(必须是函数)
*
* @param onResolved 成功的回调
* @param onRejected 失败的回调
*/
MyPromise.prototype.then = function (onResolved, onRejected){
// 向后传递成功的value
onResolved = typeof onResolved === 'function' ? onResolved : value => value
// 指定默认的失败回调(实现错误/异常传透的关键), 向后传递失败的reason
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
const that = this;
// 1. 返回一个新的promise对象
return new MyPromise((resolve, reject) => {
/**
* 调用指定的回调函数处理, 根据执行的结果, 改变return的promise的状态
*
* 3. 返回的promise的结果由回调函数 onResolved/onRejected 【异步】执行的结果决定:
* 1). 如果抛出异常, return的promise就会失败, reason为error
* 2). 如果回调函数返回的不是promise, return的promise就会成功, value就是返回的值
* 3). 如果回调函数返回的是promise, return的promise结果就是这个promise的结果
*
* @param callback 回调函数 onResolved/onRejected
*/
function handle(callback) {
try {
// 回调函数执行结果
const result = callback(that.data);
// 3). 如果回调函数返回的是promise, return的promise结果就是这个promise的结果
if (result instanceof MyPromise){
/**
* .then()获得回调函数返回的结果
* => 当result成功时,让return的promise也成功
* => 当result失败时,让return的promise也失败
* result.then(
* value => resolve(value),
* reason => reject(reason)
* )
* => 简洁版
* result.then(resolve, reject);
* 分析:result.then() 获得回调函数返回的结果
* 指定resolve接收成功的值,reject接收失败的值
*/
result.then(resolve, reject);
} else { // 2). 如果回调函数返回的不是promise, return的promise就会成功, value就是返回的值
resolve(result)
}
}catch (error) {
// 1). 异步回调函数onResolved如果抛出异常, return的promise失败(调用当前promise的reject)
reject(error)
}
}
/**
* 2. 判断当前promise状态 【that.status】
* 1). 当前promise状态是pending,将成功和失败的回调函数保存callbacks容器中缓存
* 2). 如果promise当前是resolve状态,异步执行onResolve并改变return的promise状态
* 3). 如果promise当前是reject状态,异步执行onRejected并改变return的promise状态
*/
// 1). 当前状态是pending,将回调函数保存起来
if (that.status === PENDING){
that.callbacks.push({
onResolved(value){
handle(onResolved)
},
onRejected(reason){
handle(onRejected)
}
})
}else if (that.status === RESOLVED){ // 2). 如果当前是resolve状态,异步执行onResolve并改变return的promise状态
// 0. 回调函数【异步】执行
setTimeout(() => {
handle(onResolved)
},0)
} else { // 3). 如果当前是reject状态,异步执行onRejected并改变return的promise状态
setTimeout(() => {
handle(onRejected)
},0)
}
})
};
/**
* Promise 原型对象的 catch(), 指定失败的回调函数,返回一个新的promise对象
* @param onRejected 失败的回调
*/
MyPromise.prototype.catch = function (onRejected){
return this.then(undefined, onRejected)
};
/**
* 函数对象的 resolve 方法, 返回一个【成功/失败】的promise
* 1. 判断传入的value值
* 1). 不是promise
* 返回一个成功值为value的promise
* 2). 是promise
* 根据promise的返回结果,返回成功/失败的promise
*
* @param value 接收成功的数据, 可以是一般的值, 也可以是Promise对象
*/
MyPromise.resolve = function (value){
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise){
value.then(resolve, reject)
}else {
resolve(value)
}
})
};
/**
* 函数对象的 reject 方法, 返回一个【失败】值为reason的promise对象
* @param reason 接收失败的数据
*/
MyPromise.reject = function (reason){
return new MyPromise((resolve, reject) => {
reject(reason)
})
};
/**
* 函数对象的 all 方法, 返回一个新的promise, 当所有promise都成功才成功, 否则有一个失败就失败
* @param promises 对象数组
*/
MyPromise.all = function (promises){
// 用来保存所有成功的value的数组,指定长度
const values = new Array(promises.length);
// 用来保存成功的promise的数量
let resolveCount = 0;
// 返回一个新的promise
return new MyPromise((resolve, reject) =>{
// 遍历,取每个promise的结果
promises.forEach((p, index) => {
/**
* 传入的数组中,一般情况都是promise对象,但也可以包含非promise数据
* 所以将p包装成promise对象,省去判断
*/
MyPromise.resolve(p).then(
value => {
// p成功,保存value
resolveCount++;
values[index] = value;
// 如果全部成功,将return的promise变为成功
if (resolveCount === promises.length){
resolve(values)
}
},
reason => { // 只要有一个失败了,return的promise就失败
reject(reason)
}
)
})
})
};
/**
* 函数对象的 race 方法, 返回一个新的promise, 其结果由【第一个完成】的promise结果决定
* @param promises 对象数组
*/
MyPromise.race = function (promises){
// 返回一个promise
return new MyPromise((resolve, reject) =>{
// 遍历,取每个promise的结果
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
};
/**
* 返回一个promise对象,它在指定的时间后才确定结果
* @param value
* @param time 延时时间
*/
MyPromise.resolveDelay = function(value, time){
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (value instanceof MyPromise){
value.then(resolve, reject)
}else {
resolve(value)
}
}, time)
})
};
/**
* 返回一个promise对象,它在指定的时间后才失败
* @param reason
* @param time 延时时间
*/
MyPromise.rejectDelay = function(reason, time){
return new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(reason)
}, time)
})
};
// 向外暴露模块
window.MyPromise = MyPromise
})(window);