Promise构造函数
Promise构造函数需要传的参数就是一个executor构造器函数。executor里需要传resolve和reject函数,用于改变Promise实例的状态
- 功能:立即执行executor代码,并且传递出两个函数用于改变Promise实例状态
- 参数:resolve函数和reject函数
- 返回值:无
//定义状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor){
const that = this; //保证this指向实例
this.status = PENDING; //初始化状态
this.data = undefined; //保存成功或失败回调的值
this.callbacks = []; //保存回调队列,用{onResolve,onReject}对象存储指定的回调函数队列
//更改实例状态为成功的函数
function resolve(value){
//判定当前状态是否为pending,若不是则不允许第二次更改状态
if(that.status !== PENDING) return ;
//将实例状态更改为fulfilled并保存传入的value
that.status = FULFILLED;
that.data = value;
//检查回调队列有没有回调函数需要调用
if (that.callbacks.length > 0) {
//将成功回调推入微队列异步执行
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onResolve(that.data));
});
}
}
//更改实例状态为失败的函数
function reject(reason){
//判定当前状态是否为pending,若不是则不允许第二次更改状态
if(that.status !== PENDING) return ;
//将实例状态更改为rejected并保存传入的reason
that.status = REJECTED;
that.data = reason;
//检查回调队列有没有回调函数需要调用
if (that.callbacks.length > 0) {
//将失败回调推入微队列异步执行
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onResolve(that.data));
});
}
}
//同步执行executor,并向外传递出改变实例状态的函数
executor(resolve,reject);
}
Promise.prototype.then()
- 功能:给实例对象指定成功和失败的回调
- 参数:成功的回调函数和失败的回调函数
- 返回值:return一个新的Promise实例
- 特性:return的Promise实例状态根据传入回调函数的执行结果决定
- return的Promise状态影响因素
- 回调函数执行抛出异常,return的新Promise状态为rejected,reason为该异常
- 回调函数返回非Promise值,return的新Promise状态为fulfilled,value为回调函数的返回值
- 回调函数返回Promise值,return的新Promise状态和值都跟随返回的Promise
Promise.prototype.then = function(onResolve,onReject){
const that = this;
//判定传入的成功回调是否为函数,若不是则强制改为函数
onResolve = typeof onResolve === 'function' ? onResolve : value => value ;
//判定传入的失败回调是否为函数,若不是则原样抛出异常,实现异常穿透
onReject = typeof onReject === 'function' ? onReject : reason => {throw reason};
return new Promise((resolve,reject)=>{
//定义handle函数处理所有能影响return的Promise状态的情况
function handle(callback){
//1.若回调函数执行抛出异常则捕获异常
try{
const res = callback(that.data); //接收成功回调的返回值
//判断返回值类型并处理
if(res instanceof Promise){
//3.根据res的状态决定return的Promise状态
res.then(resolve,reject);
}else{ //2.非Promise返回值直接返回
resolve(res);
}
}catch(error){
reject(error);
}
}
//若此时是先指定了回调函数,后面改变的状态则将回调放入回调队列
if(that.status === PENDING){
that.callbacks.push(
{
onResolve(value){
handle(onResolve);
},
onReject(reason){
handle(onReject);
}
}
)
}else if(that.status === FULFILLED){ //若先改变了状态,则直接将回调函数推入微队列执行
queueMicrotask(()=>{
handle(onResolve);
})
}else{
queueMicrotask(()=>{
handle(onReject);
})
}
})
}
Promise.prototype.catch()
- 功能:给实例对象指定失败的回调
- 参数:失败的回调函数
- 返回值:return一个新的Promise实例
- 特性:return的Promise实例状态根据传入回调函数的执行结果决定
- return的Promise状态影响因素
- 回调函数执行抛出异常,return的新Promise状态为rejected,reason为该异常
- 回调函数返回非Promise值,return的新Promise状态为fulfilled,value为回调函数的返回值
- 回调函数返回Promise值,return的新Promise状态和值都跟随返回的Promise
Promise.prototype.catch = function(onReject){
return this.then(undefined,onReject);
}
Promise.resolve()
- 功能:根据传入的value返回一个已经改变了状态的Promise
- 参数:value
- 返回值:return一个新的Promise实例
- 特性:return的Promise实例状态根据传入value决定
- return的Promise状态影响因素 2. value是一个非Promise,return的新Promise状态为fulfilled,value为回调函数的返回值 3. value是一个Promise,return的新Promise状态和值都跟随返回的Promise
//仅需根据then中handle函数的逻辑重写一遍即可
Promise.resolve = function(value){
return new Promise((resolve,reject)=>{
if(value instanceof Promise){
value.then(resolve,reject);
}else{
resolve(value);
}
})
}
Promise.reject()
- 功能:根据传入的value返回一个已经改变了状态的Promise
- 参数:reason
- 返回值:return一个新的rejected状态的Promise实例
- 特性:return的Promise实例状态一定是rejected
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
if(reason instanceof Error){
reject(reason.message);
}else if(reason instanceof Promise){
reject(reason.data);
}else{
reject(reason);
}
})
}
Promise.all()
- 功能:根据传入的Promise数组,若该数组的Promise最后全都成功则返回一个fulfilled的Promise,否则返回一个rejected的Promise
- 参数:Promise数组
- 返回值:return一个Promise实例
- 特性:return的Promise实例状态根据传入的Promise数组决定
Promise.all = function(promiseArr){
const values = [];//定义一个values保存成功Promise的value的值
let count = 0; //记录有几个Promise成功
return new Promise((resolve,reject)=>{
//遍历数组所有元素
promiseArr.forEach((p,index)=>{
Promise.resolve(p).then( //用Promise.resolve包裹,处理数组中有非Promise值的情况
value => {
++count;
values[index] = value;
if(count === promiseArr.length) resolve(values);
},
reason => reject(reason))
});
})
}
Promise.race()
- 功能:根据传入的Promise数组,return的Promise状态跟随第一个完成的Promise
- 参数:Promise数组
- 返回值:return一个Promise实例
- 特性:return的Promise实例状态跟随第一个完成的Promise
Promise.race = function(promiseArr){
return new Promise((resolve,reject)=>{
promiseArr.forEach((p)=>{
Promise.resolve(p).then( //用Promise.resolve包裹,处理数组中有非Promise值的情况
value => resolve(value),
reason => reject(reason)
)
})
})
}
完整代码
ES5版
(function (w) {
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor) {
const that = this;
that.status = PENDING;
that.data = undefined;
that.callbacks = [];
function resolve(value) {
if (that.status !== PENDING) return;
that.status = FULFILLED;
that.data = value;
if (that.callbacks.length > 0) {
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onResolve(that.data));
});
}
};
function reject(reason) {
if (that.status !== PENDING) return;
that.status = REJECTED;
that.data = reason;
if (that.callbacks.length > 0) {
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onReject(that.data));
});
}
};
executor(resolve, reject);
};
Promise.prototype.then = function (onResolve, onReject) {
const that = this;
onResolve = typeof onResolve === 'function' ? onResolve : value => value;
onReject = typeof onReject === 'function' ? onReject : reason => { throw reason };
return new Promise((resolve, reject) => {
function handle(callback) {
try {
const res = callback(that.data);
if (res instanceof Promise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
}
if (that.status === PENDING) {
that.callbacks.push(
{
onResolve(value) {
handle(onResolve);
},
onReject(reason) {
handle(onReject);
}
}
)
} else if (that.status === FULFILLED) {
queueMicrotask(() => {
handle(onResolve);
})
} else {
queueMicrotask(() => {
handle(onReject);
})
};
});
};
Promise.prototype.catch = function (onReject) {
return this.then(undefined, onReject);
};
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
}else {
resolve(value);
}
})
};
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
if (reason instanceof Error) {
reject(reason.message);
} else if (reason instanceof Promise) {
reject(reason.data);
} else {
reject(reason);
}
})
};
Promise.all = function (promiseArr) {
const values = [];
let count = 0;
return new Promise((resolve, reject) => {
promiseArr.forEach((p, index) => {
Promise.resolve(p).then(
value => {
++count;
values[index] = value;
if (count === promiseArr.length) resolve(values);
},
reason => reject(reason))
});
})
};
Promise.race = function (promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach((p) => {
Promise.resolve(p).then(
value => resolve(value),
reason => reject(reason)
)
})
})
};
w.Promise = Promise;
})(window)
ES6版
(function (w) {
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class Promise {
constructor(executor) {
const that = this;
that.status = PENDING;
that.data = undefined;
that.callbacks = [];
function resolve(value) {
if (that.status !== PENDING) return;
that.status = FULFILLED;
that.data = value;
if (that.callbacks.length > 0) {
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onResolve(that.data));
});
}
}
function reject(reason) {
if (that.status !== PENDING) return;
that.status = REJECTED;
that.data = reason;
if (that.callbacks.length > 0) {
queueMicrotask(() => {
that.callbacks.forEach(cb => cb.onReject(that.data));
});
}
}
executor(resolve, reject);
};
then(onResolve, onReject) {
const that = this;
onResolve = typeof onResolve === 'function' ? onResolve : value => value;
onReject = typeof onReject === 'function' ? onReject : reason => { throw reason };
return new Promise((resolve, reject) => {
function handle(callback) {
try {
const res = callback(that.data);
if (res instanceof Promise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
}
if (that.status === PENDING) {
that.callbacks.push(
{
onResolve(value) {
handle(onResolve);
},
onReject(reason) {
handle(onReject);
}
}
)
} else if (that.status === FULFILLED) {
queueMicrotask(() => {
handle(onResolve);
})
} else {
queueMicrotask(() => {
handle(onReject);
})
};
});
};
catch(onReject) {
return this.then(undefined, onReject);
};
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
}else {
resolve(value);
}
})
};
static reject(reason) {
return new Promise((resolve, reject) => {
if (reason instanceof Error) {
reject(reason.message);
} else if (reason instanceof Promise) {
reject(reason.data);
} else {
reject(reason);
}
})
};
static all(promiseArr) {
const values = [];
let count = 0;
return new Promise((resolve, reject) => {
promiseArr.forEach((p, index) => {
Promise.resolve(p).then(
value => {
++count;
values[index] = value;
if (count === promiseArr.length) resolve(values);
},
reason => reject(reason))
});
})
};
static race(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach((p) => {
Promise.resolve(p).then(
value => resolve(value),
reason => reject(reason)
)
})
})
};
}
w.Promise = Promise;
})(window)