概念
笔者的理解呢,就是用来解决大量回调函数嵌套出现的回调地狱
问题以及封装一些异步的代码逻辑。
Promise的一些现象
Promise 是一个构造函数
Promise 接收一个函数,这个函数有两个参数
resovle
和rejected
,也要求是函数Promise 实例化后的对象,包含一个
then
函数,then
函数接收两个参数,这两个参数一般也是函数使用 new 关键字调用 Promise 构造函数,结束时:
如果正确执行,调用 resolve 方法,将结果放在 resolve 的参数中执行,这个结果可以放在后面的 then 中的第一个函数(onfulfilled)参数中拿到;
如果错误执行,调用 reject 方法,将错误信息放在 resovle 的参数中执行,这个结果可以放在后面的 then 中的第二个函数(onrejected)参数中拿到。
const promise = new Promise((resovle,rejected) => {
setTimeout(() => {
const random_number = Math.floor(Math.random() * 100);
if(random_number % 2 === 0){
resovle('是偶数');
}else{
rejected('是奇数');
}
},1000);
});
promise.then((value) => {
console.log("resovle: "+value);
} , (error) => {
console.log("rejected: "+error);
});
知道了这些现象后,我们来手写一下 Promise 吧!
Promise 规范
status(状态)
1、pending
初始状态,可改变。
一个 promise 对象在 没有调动resolve
、reject
这两个方法前都处于这个状态。
我们可以通过调用resovle
或者reject
方法,让这个 promise 对象,变成 fulfilled
或者rejected
状态。
2、fulfilled
不可变状态
在resovle
之后,变成这个状态,拥有一个value
。
3、rejected
不可变状态。
在reject
之后,变成这个状态,拥有一个reason
。
then 函数
1、参数
onFulfilled
必须是函数类型,如果不是,应该被忽略;
onRejected
必须是函数,如果不是,应该被忽略。
2、onFulfilled 和 onRejected 的特性
在 promise 对象变成 fulfilled
或者rejected
状态的时候,应该调用 onFulfilled
或者 onRejected
。
3、then 可以被多次调用
promise 的状态变成fulfilled
或者rejected
后,所有的onFulfilled
或者onRejected
都按照 then 的顺序执行,也就是按照注册顺序执行。
4、then 应该返回一个 promise 对象
onFulfilled 或者 onRejected 执行的结果为x,调用 resovlePromise;
如果 onFulfilled 或者 onRejected 执行时抛出异常,返回的 promise对象 需要被 reject;
如果 onFulfilled 或者onRejected 不是一个函数,返回的 promise对象 以原来 promise对象的 value 或者 reason 触发 fulfulled 或者 rejected。
5、resovlePromise的规范
。。。。。(感兴趣自己去了解吧)
手写 Promise
第一版
function MyPromise01(executor){
this.status = 'pending';
this.value = null;
this.reason = null;
const resolve = (value) => {
if(this.status === 'pending'){
this.status = 'fulfilled';
this.value = value;
}
}
const reject = (reason) => {
if(this.status === 'pending'){
this.status = 'rejected';
this.reason = reason;
}
}
executor(resolve,reject);
}
MyPromise01.prototype.then = function(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => {throw error};
if(this.status === 'fulfilled'){
onFulfilled(this.value);
}
if(this.status === 'rejected'){
onRejected(this.reason);
}
}
缺陷:无法处理异步任务。
第二版:发布订阅模式解决异步更改promise状态问题
function MyPromise02(executor) {
this.status = 'pending';
this.value = null;
this.reason = null;
this.onFulfilledArray = [];
this.onRejectedArray = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledArray.forEach(func => func(value));
}
}
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedArray.forEach(func => func(reason));
}
}
executor(resolve, reject);
}
MyPromise02.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw new Error(error) };
if (this.status === 'fulfilled') {
onFulfilled(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
if(this.status === 'pending'){
this.onFulfilledArray.push(onFulfilled);
this.onRejectedArray.push(onRejected);
}
}
第三版:解决链式调用的问题
function MyPromise03(executor) {
this.status = 'pending';
this.value = null;
this.reason = null;
this.onFulfilledArray = [];
this.onRejectedArray = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledArray.forEach(func => func(value));
}
}
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedArray.forEach(func => func(reason));
}
}
executor(resolve, reject);
}
MyPromise03.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw new Error(error) };
if (this.status === 'fulfilled') {
return new MyPromise02((resolve, reject) => {
try {
let result = onFulfilled(this.value);
resolve(result);
} catch (e) {
reject(e);
}
});
}
if (this.status === 'rejected') {
return new MyPromise02((resolve, reject) => {
try {
let result = onRejected(this.reason);
resolve(result);
} catch (e) {
reject(e);
}
});
}
if (this.status === 'pending') {
return new MyPromise02((resolve, reject) => {
try {
this.onFulfilledArray.push(() => {
let result = onFulfilled(this.value);
resolve(result);
});
} catch (e) {
this.onRejectedArray.push(() => {
reject(e);
});
}
});
}
}
好了,基本上就这样吧。。。最后的 resovlePromise 规范的实现,我也无能为力了。。。
(你能手写到这里,已经OK了!!!剩下可以讲给面试官听,你对resovlePromise 规范的理解)
Promise 相关问题
1、如何并发执行 promise?
const promiseArrayGenerator = num => {
return new Array(num).fill(0).map((item,index) => {
return new Promise((resolve,reject) => {
setTimeout(()=>{
resolve(index);
},Math.random() * 1000);
})
});
}
const proArr = promiseArrayGenerator(100);
Promise.all(proArr).then(res => console.log(res));
输出:
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99
]
2、顺序执行Promise
const promiseArrayGenerator = num => {
return new Array(num).fill(0).map((item,index) => {
return new Promise((resolve,reject) => {
setTimeout(()=>{
resolve(index);
},Math.random() * 1000);
})
});
}
const proArr = promiseArrayGenerator(100);
((proArr)=>{
proArr.reduce((proChain,pro) =>{
return proChain.then(res => {
~res && console.log(res);
return pro;
})
},Promise.resolve(-1)).then(res => console.log(res));
})(proArr);
3、pipe 保证并发量的处理
const promiseArrayGenerator = num => {
return new Array(num).fill(0).map((item,index) => {
return new Promise((resolve,reject) => {
setTimeout(()=>{
resolve(index);
},Math.random() * 1000);
})
});
}
const proArr = promiseArrayGenerator(100);
const promisePipe = (proArr,concurrent) => {
if(concurrent > proArr.length){
return Promise.all(proArr).then(res => console.log(res));
}
let _arr = [...proArr];
for(let i=0;i<concurrent;i++){
let fn = _arr.shift();
run(fn);
}
function run(fn){
fn.then(res => {
console.log(res);
if(_arr.length){
run(_arr.shift());
}
})
}
}
// 100个函数,10个并发
promisePipe(proArr,10);
4、设计 wrap 方法,包裹 Promise ,可以随时 abort 掉
const warp = function(promise){
let _reject;
const obj = Promise.race([promise,new Promise((resolve,reject)=>{
_reject = reject;
})]);
obj.abort = function(){
_reject('abort');
}
return obj;
}
(Promise确实难以理解,尽量去积累扩展吧)
2024.11.19
writeBy kaiven