手写Promise
个人学习笔记,不保证全部正确,参考即可
大纲
- 对象属性
1.状态:status
2.数据:data
3.回调函数的数组:callbacks - 构造函数内部的方法
1.resolve //传给回调函数调用,改变Promise的状态,status:“resolved”
2.reject //传给回调函数调用,改变Promise的状态,status:“rejected” - 原型上的方法
1.then //返回一个新的Promise对象,实现链式调用,根据回调函数中return的值改变新Promise的状态
2.catch //返回一个新的Promise对象,新Promise状态改为失败(rejected) - 函数对象的方法
1.resolve //返回一个新的Promise,新Promise状态根据return的内容而定
2.reject //返回一个新的Promise,新Promise状态改为失败(rejected)
3.all
4.race
(function (window) {
// 状态常量
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
/*
Promise构造函数
resolve方法
reject方法
*/
function Promise (excutor) {
// 保存this
const that = this;
that.status = PENDING; // Promise的状态
that.data = undefined; // 存放数据
that.callbacks = []; // 存放预先指定的回调函数
// 成功时调用
function resolve (value) {
if(that.status !== PENDING){
return;
}
// 改变状态
that.status = RESOLVED;
// 存放数据
that.data = value;
// 判断是否是先指定了回调函数,是就执行数组中的回调函数
if (that.callbacks.length > 0) {
setTimeout(() => {
that.callbacks.forEach(callbackObj => {
callbackObj.onResolved(value);
});
})
}
}
// 失败时调用
function reject (reason) {
if(that.status !== PENDING){
return;
}
// 改变状态
that.status = REJECTED;
// 存放数据
that.data = reason;
// 判断是否是先指定了回调函数,是就执行数组中的回调函数
if (that.callbacks.length > 0) {
setTimeout(() => {
that.callbacks.forEach(callbackObj => {
callbackObj.onRejected(reason);
});
})
}
}
// 捕获异常,应对throw的情况
try{
// 调用执行器,将resolve和reject方法传入
excutor(resolve, reject);
} catch (err) {
// 如果直接抛出异常,就调用reject
reject(err)
}
}
/*
原型中的then,处理成功和失败的回调函数
返回一个新的Promise,实现链式调用
异常穿透
*/
Promise.prototype.then = function (onResolved, onRejected){
// 保存this
const that = this;
// 预防没写回调函数,都变为函数
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
// 异常穿透
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
// 返回一个新的Promise,实现链式调用
return new Promise((resolve, reject) => {
// handle处理回调函数中return的结果
function handle (callback) {
try{
// 得到回调函数的结果
const result = callback(that.data);
// 如果回调结果为Promise
if(result instanceof Promise){
result.then(resolve, reject)
} else {
// 否则就直接传值给下一个then
resolve(result);
}
} catch (err) {
// 如果回调函数中的return是throw异常,就直接调用下一个then的失败回调函数
reject(err);
}
}
// 根据当前Promise的状态,异步处理对应的回调函数,并处理新Promise的状态,以便下一个then进行回调
if (that.status === RESOLVED) {
// setTimeout是为了加入js回调栈中,实现异步处理
setTimeout(() => {
handle(onResolved);
})
} else if (that.status === REJECTED) {
setTimeout(() => {
handle(onRejected);
})
} else { // 如果当前状态是pending,说明是先指定了回调函数,要把回调函数放入数组中
that.callbacks.push({
onResolved (value) {
handle(onResolved);
},
onRejected (reason) {
handle(onRejected);
}
})
}
})
}
/*
原型中的catch,处理失败的回调函数
返回一个新的Promise
*/
Promise.prototype.catch = function (onRejected){
return this.then(undefined, onRejected);
}
/*
resolve方法,返回成功的Promise,或者失败的Promise
*/
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if(value instanceof Promise){ // 如果是Promise,返回该Promise的结果
value.then(resolve, reject);
} else { //如果是值,就直接返回成功的Promise
resolve(value);
}
})
}
/*
reject方法,返回失败的Promise
*/
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
/*
Promise函数对象方法all
返回一个新的Promise
所有的Promise成功才返回成功的Promise,否则返回失败的Promise
值的顺序不能乱
*/
Promise.all = function (promises) {
// 保存成功的value值
const values = new Array(promises.length);
// 记录成功的promise数
let resolveCount = 0;
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
values[index] = value;
// 数量加1
resolveCount ++;
// 判断是否已经全部成功,是就返回成功的Promise
if(resolveCount === promises.length){
resolve(values)
}
},
// 如果有一个失败,就返回失败的Promise
reason => {
reject(reason)
}
)
})
})
}
/*
Promise函数对象方法race
返回一个新的Promise
所有的Promise成功才返回成功的Promise,否则返回失败的Promise
值的顺序由执行时间来决定
*/
Promise.race = function (promises) {
// 保存成功的value值
const values = new Array(promises.length);
// 记录成功的promise数
let resolveCount = 0;
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
// Promise.resolve(p)的作用是将数组中不是Promise对象的元素也编程Promise对象
Promise.resolve(p).then(
value => {
resolve(value)
},
// 如果有一个失败,就返回失败的Promise
reason => {
reject(reason)
}
)
})
})
}
//暴露Promise
window.Promise = Promise;
})(window)