先简单回顾一下Promise
1. Promise构造函数: Promise (excutor) {}
excutor函数: 同步执行 (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
2. Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数 (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象
3. Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
4. Promise.resolve方法: (value) => {}
value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象
5. Promise.reject方法: (reason) => {}
reason: 失败的原因
说明: 返回一个失败的promise对象
6. Promise.all方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的(最先完成的)promise的结果、状态就是最终的结果、状态
复制代码
步骤
1. 定义整体结构
(function(window) {
// 定义promise的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 定义Promise构造函数 excutor: 执行器函数(同步执行)
function Promise(excutor) {
if(typeof excutor !== 'function') throw new TypeError(`Promise resolver ${excutor} is not a function`);
// 定义resolve、reject函数
const resolve = value => { }
const reject = reason => { }
try {
// 立即同步执行excutor函数,将resolve、reject函数作为其参数供之后调用
excutor(resolve, reject);
} catch (error) {
// 如果excutor函数抛出异常,promise对象变为fulfilled状态
reject(error);
}
}
// 定义then方法
Promise.prototype.then = function (onResolved, onRejected) { }
// 定义catch方法
Promise.prototype.catch = function (onRejected) { }
// 定义Promise.resolve方法
Promise.resolve = function (value) { }
// 定义Promise.reject方法
Promise.reject = function (reason) { }
// 定义Promise.all方法
Promise.all = function (promises) { }
// 定义Promise.race方法
Promise.race = function (promises) { }
//向外暴露Promise构造函数
window.Promise = Promise;
})(window)
复制代码
2. Promise构造函数的实现
function Promise(excutor) {
if (typeof excutor !== 'function') throw new TypeError(`Promise resolver ${excutor} is not a function`);
// 定义promise对象的初始状态、结果以及其状态为PENDING时then方法将来会调用的回调函数集合
this.PromiseState = PENDING;
this.PromiseResult = undefined;
this.callbacks = []; // 存储结构:[{onResolve(){}, onRejectd(){}}]
const resolve = value => {
if (this.PromiseState !== PENDING) return; //因为状态只能改变一次,所以要判断一下如果当前状态不是PENDING,如果是则直接结束
this.PromiseState = FULFILLED; //将状态改为FULFILLED
this.PromiseResult = value; //保存value数据
//如果有待执行的callback函数,将其放入微任务队列执行,queueMicrotask是windows下的一个可以发起微任务的函数
if (this.callbacks.length > 0) {
queueMicrotask(() => {
this.callbacks.forEach(callback => {
callback.onResolved(value);
});
});
}
}
const reject = reason => {
if (this.PromiseState !== PENDING) return;
this.PromiseState = REJECTED;
this.PromiseResult = reason;
if (this.callbacks.length > 0) {
queueMicrotask(() => {
//放入队列中执行所有失败的回调
this.callbacks.forEach(callback => {
callback.onRejected(reason);
});
});
}
}
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
}
}
复制代码
3. then方法的实现
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason; //向后传递失败的reason,指定默认的失败状态回调(实现错误/异常传透的关键点)
};
const _this = this;
//返回一个新的promise对象,该对象的状态和值由回调函数onResolved()和onRejected()的返回值决定
return new Promise((resolve, reject) => {
// 调用指定的回调函数,根据执行结果,改变return的promise的状态和结果
const handle = callback => {
/*
1. 如果回调函数返回值是promise对象,return的promise状态和结果就是这个回调函数返回的promise对象的状态和结果
2. 如果回调函数返回值不是promise对象,return的promise就会是FULFILLED状态,value就是返回的值
3. 如果抛出异常,return的promise就会是REJECTED状态,reason是error
*/
try {
const result = callback(_this.PromiseResult);
//如果result为FULFILLED状态则调用resolve方法,反之则调用reject方法
(result instanceof Promise) ? result.then(resolve, reject) : resolve(result);
} catch (error) {
reject(error)
}
}
//如果当前状态是PENDING则把回调函数保存起来,否则放进微任务队列中执行回调函数。
const options = {
[PENDING]() {
_this.callbacks.push({
onResolved(value) {
handle(onResolved);
},
onRejected(reason) {
handle(onRejected);
}
});
},
[FULFILLED]() {
queueMicrotask(() => handle(onResolved));
},
[REJECTED]() {
queueMicrotask(() => handle(onRejected));
}
};
options[_this.PromiseState]();
});
}
复制代码
4. catch方法的实现
// catch方法:简化版then方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
复制代码
4. Promise.resolve方法的实现
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
// 如果value是promise对象,使用value的状态和结果作为promise的状态结果,否则则返回一个结果是value状态是FULFILLED的promise对象
(value instanceof Promise) ? value.then(resolve, reject) : resolve(value);
});
}
复制代码
5. Promise.reject方法的实现
Promise.reject = function (reason) {
//返回一个状态为RJECTED的promise对象
return new Promise((resolve, reject) => reject(reason));
}
复制代码
6. Promise.all方法的实现
Promise.all = function (promises) {
//定义一个用于保存所有状态为FULFILLED的promise对象value的数组以及用于保存FULFILLED状态的promise对象数量的变量
const values = new Array(promises.length);
let resolvedCount = 0;
return new Promise((resolve, reject) => {
//遍历promise获取每个promise的结果
promises.forEach((p, index) => {
//如果数组中的元素不是promise对象,则将其变为成功的promise对象
Promise.resolve(p).then(
value => { //p为FULFILLED状态,将其value保存到values中,FULFILLED状态的promise对象数量+1
resolvedCount++;
/*
注意:
不能用values.push(value),因为then()中的回调函数时异步的,所以我们无法确定谁先执行完,
结果就是先执行完回调函数的value先添加至数组values中,导致values中value不能与promises数组中的promise对象一一对应。
解决方法:
values[index] = value;这样不管哪个回调函数先执行完,都会放在对应的位置上。
*/
values[index] = value;
/*
如果所有的promise对象都是FULFILLED状态,将return的promise对象状态变为FULFILLED
注意:
为什么不用values.length === promises.length作为判断条件?
这是因为上一步values[index] = value的原因,假如最后一个promise的onResolved()先执行完,则values.length === promises.length,这时会直接执行resolve(values);
解决方法:
定义一个变量resolvedCount = 0,每执行一次onResolved()就+1
*/
if (resolvedCount === promises.length) resolve(values);
},
/*
假如有多个REJECTED状态的promise对象,reject(reason);会调用多次吗?前面调用的reject会被覆盖吗?
会调用多次,但后面调用的不会将前面覆盖,因为一个promise对象的状态只能更改一次,
当调用reject的时候,函数内部会首先判断该promise的对象状态是否为PENDING,如果不是,就则直接return了。
*/
reject
)
})
});
}
复制代码
7. Promise.race方法的实现
Promise.race = function (promises) {
//返回一个promise,其结果由第一个完成的promise决定
return new Promise((resolve, reject) => {
promises.forEach(p => {
//如果数组中的元素不是promise对象,则将其变为FULFILLED状态的promise对象
Promise.resolve(p).then(resolve, reject);
})
});
}
复制代码
代码汇总,引入即可运行
(function (window) {
// 定义promise的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 定义Promise构造函数 excutor: 执行器函数(同步执行)
function Promise(excutor) {
if (typeof excutor !== 'function') throw new TypeError(`Promise resolver ${excutor} is not a function`);
// 定义promise对象的初始状态、结果以及其状态为PENDING时then方法将来会调用的回调函数集合
this.PromiseState = PENDING;
this.PromiseResult = undefined;
this.callbacks = []; // 存储结构:[{onResolve(){}, onRejectd(){}}]
const resolve = value => {
if (this.PromiseState !== PENDING) return; //因为状态只能改变一次,所以要判断一下如果当前状态不是PENDING,如果是则直接结束
this.PromiseState = FULFILLED; //将状态改为FULFILLED
this.PromiseResult = value; //保存value数据
//如果有待执行的callback函数,立即异步执行回调
if (this.callbacks.length > 0) {
queueMicrotask(() => {
this.callbacks.forEach(callback => {
callback.onResolved(value);
});
});
}
}
const reject = reason => {
if (this.PromiseState !== PENDING) return;
this.PromiseState = REJECTED;
this.PromiseResult = reason;
if (this.callbacks.length > 0) {
queueMicrotask(() => {
//放入队列中执行所有失败的回调
this.callbacks.forEach(callback => {
callback.onRejected(reason);
});
});
}
}
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
}
}
// 定义then方法
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason; //向后传递失败的reason,指定默认的失败状态回调(实现错误/异常传透的关键点)
};
const _this = this;
//返回一个新的promise对象,该对象的状态和值由回调函数onResolved()和onRejected()的返回值决定
return new Promise((resolve, reject) => {
// 调用指定的回调函数,根据执行结果,改变return的promise的状态和结果
const handle = callback => {
/*
1. 如果回调函数返回值是promise对象,return的promise状态和结果就是这个回调函数返回的promise对象的状态和结果
2. 如果回调函数返回值不是promise对象,return的promise就会是FULFILLED 状态,value就是返回的值
3. 如果抛出异常,return的promise就会是REJECTED状态,reason是error
*/
try {
const result = callback(_this.PromiseResult);
//如果result为FULFILLED 状态则调用resolve方法,反之则调用reject方法
(result instanceof Promise) ? result.then(resolve, reject) : resolve(result);
} catch (error) {
reject(error)
}
}
//如果当前状态是PENDING则把回调函数保存起来,否则放进宏任务队列中执行回调函数。
const options = {
[PENDING]() {
_this.callbacks.push({
onResolved(value) {
handle(onResolved);
},
onRejected(reason) {
handle(onRejected);
}
});
},
[FULFILLED]() {
queueMicrotask(() => handle(onResolved));
},
[REJECTED]() {
queueMicrotask(() => handle(onRejected));
}
};
options[_this.PromiseState]();
});
}
// 定义catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
// 定义Promise.resolve方法
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
// 如果value是promise对象,使用value的状态和结果作为promise的状态结果,否则则返回一个结果是value状态是FULFILLED 的promise对象
(value instanceof Promise) ? value.then(resolve, reject) : resolve(value);
});
}
// 定义Promise.reject方法
Promise.reject = function (reason) {
//返回一个状态为REJECTED的promise对象
return new Promise((resolve, reject) => reject(reason));
}
// 定义Promise.all方法
Promise.all = function (promises) {
//定义一个用于保存所有状态为FULFILLED 的promise对象value的数组以及用于保存FULFILLED 状态的promise对象数量的变量
const values = new Array(promises.length);
let resolvedCount = 0;
return new Promise((resolve, reject) => {
//遍历promise获取每个promise的结果
promises.forEach((p, index) => {
//如果数组中的元素不是promise对象,则将其变为成功的promise对象
Promise.resolve(p).then(
value => { //p为FULFILLED 状态,将其value保存到values中,FULFILLED 状态的promise对象数量+1
resolvedCount++;
/*
注意:
不能用values.push(value),因为then()中的回调函数时异步的,所以我们无法确定谁先执行完,
结果就是先执行完回调函数的value先添加至数组values中,导致values中value不能与promises数组中的promise对象一一对应。
解决方法:
values[index] = value;这样不管哪个回调函数先执行完,都会放在对应的位置上。
*/
values[index] = value;
/*
如果所有的promise对象都是FULFILLED 状态,将return的promise对象状态变为FULFILLED
注意:
为什么不用values.length === promises.length作为判断条件?
这是因为上一步values[index] = value的原因,假如最后一个promise的onResolved()先执行完,则values.length === promises.length,这时会直接执行resolve(values);
解决方法:
定义一个变量resolvedCount = 0,每执行一次onResolved()就+1
*/
if (resolvedCount === promises.length) resolve(values);
},
/*
假如有多个REJECTED状态的promise对象,reject(reason);会调用多次吗?前面调用的reject会被覆盖吗?
会调用多次,但后面调用的不会将前面覆盖,因为一个promise对象的状态只能更改一次,
当调用reject的时候,函数内部会首先判断该promise的对象状态是否为PENDING,如果不是,就则直接return了。
*/
reject
)
})
});
}
// 定义Promise.race方法
Promise.race = function (promises) {
//返回一个promise,其结果由第一个完成的promise决定
return new Promise((resolve, reject) => {
promises.forEach(p => {
//如果数组中的元素不是promise对象,则将其变为FULFILLED 状态的promise对象
Promise.resolve(p).then(resolve, reject);
})
});
}
//向外暴露Promise构造函数
window.Promise = Promise;
})(window)
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END