Promise
手写一个 promise
- testP = new testPromise()
1. 实例化的 p
<script type="module">
const testP = new testPromise((resolve, reject) => {
// resolve('我成功了!');
reject('我失败了!');
});
console.log(testP, 'testP');
</script>
class testPromise {
constructor(handle){
this['[[PromiseState]]'] = 'pending'; // promise 执行的状态
this['[[PromiseResult]]'] = undefined; // 存放的值
handle(this.resolve.bind(this), this.reject.bind(this))
};
resolve(value) {
this.status = 'fulfilled';
this.result = value;
};
reject(err) {
this.status = 'rejected';
this.result = err;
};
};
2. P.then(onResolved, onRejected)
- 回调函数 异步执行 onResolved 获取 Promise 中 resolve('我成功了!') 传出来的值,onRejected 获取 Promise 中 reject('我失败了!') 传出来的值
<script type="module">
const testP = new testPromise((resolve, reject) => {
// resolve('我成功了!');
reject('我失败了!');
});
testP.then((res) => {
console.log(res, 'testP1');
}, err => {
console.log(err, 'err1')
});
testP.then((res) => {
console.log(res, 'testP2');
}, err => {
console.log(err, 'err2')
});
// then 的链式调用
testP.then((res) => {
// console.log(res, 'testP1');
let a = `${res} + testP1`
return a
}, err => {
console.log(err, 'err1')
return '我错了'
}).then(res => {
console.log(res, 'res2')
});
</script>
class testPromise {
constructor(handle){
this['[[PromiseState]]'] = 'pending'; // promise 执行的状态
this['[[PromiseResult]]'] = undefined; // 存放的值
// 存储函数
this.resolveQueue = [];
this.rejectQueue = [];
handle(this.resolve.bind(this), this.reject.bind(this))
};
resolve(value) {
this['[[PromiseState]]'] = 'fulfilled';
this['[[PromiseResult]]'] = value;
const run = () => {
let cb;
while(cb = this.resolveQueue.shift()){
cb && cb(value);
}
};
setTimeout(()=> {
run();
},1000)
};
reject(err) {
this['[[PromiseState]]'] = 'rejected';
this['[[PromiseResult]]'] = err;
const run = () => {
let cb;
while(cb = this.rejectQueue.shift()){
cb && cb(err);
}
};
setTimeout(()=> {
run();
},1000)
};
then(onResolved, onRejected) {
this.resolveQueue.push(onResolved);
this.rejectQueue.push(onRejected);
}
};
resolveQueue和rejectQueue是存放执行函数的,之所以是数组是因为可以多次调用,如果不用数组的话,就会执行最后一个,其中存放的函数必须要在resolve或reject执行完毕之后在执行,从而获取value或err的值,此时在run加一个定时器就是为了满足这个需求,但是这样会出现一个新的问题,promise.then() 中的回调函数是 异步微任务,其执行的顺序应该在定时器之前,对于这个问题目前有两个结局方案:
resolve(value) {
this['[[PromiseState]]'] = 'fulfilled';
this['[[PromiseResult]]'] = value;
const run = () => {
let cb;
while(cb = this.resolveQueue.shift()){
cb && cb(value);
}
};
// setTimeout(()=> {
// run();
// },1000)
const observer = new MutationObserver(run);
observer.observe(document.body, { attributes: true });
document.body.setAttribute('key', 'value')
};
reject(err) {
this['[[PromiseState]]'] = 'rejected';
this['[[PromiseResult]]'] = err;
const run = () => {
let cb;
while(cb = this.rejectQueue.shift()){
cb && cb(err);
}
};
// setTimeout(()=> {
// run();
// },1000)
// queueMicrotask 是用来执行微任务的,绑定在 window 上
queueMicrotask(
run
);
};
-
第一种:
监听属性的变化是微任务,第二种queueMicrotask是用来执行微任务的 -
promise.then()的链式调用
then(onResolved, onRejected) {
return new testPromise((resolve, reject) => {
// 要判断 return 的是不是 Promise 对象
let resolveFn = (value) => {
let result = onResolved && onResolved(value);
if(result instanceof testPromise) {
// 执行 result.then 是递归 其中的 resolve 方法 是为了获取最后的值
result.then(
resolve
)
} else {
resolve(result);
}
}
this.resolveQueue.push(resolveFn);
let rejectFn = (err) => {
onRejected && onRejected(err);
reject()
}
this.rejectQueue.push(rejectFn);
})
}
- promise.then的链式调用,
promise.then()返回的是 Promise 对象
then(onResolved, onRejected) {
return new testPromise((resolve, reject) => {
// 要判断 return 的是不是 Promise 对象
let resolveFn = (value) => {
let result = onResolved && onResolved(value);
if(result instanceof testPromise) {
// 执行 result 中的 resolve 方法
result.then(
resolve
)
} else {
resolve(result);
}
}
this.resolveQueue.push(resolveFn);
let rejectFn = (err) => {
onRejected && onRejected(err);
reject()
}
this.rejectQueue.push(rejectFn);
})
};
3. Promise.resolve() 和 Promise.reject( )
- 将 Promise 转化成当前所需的 Promise 对象
<script type="module">
const pResolve = testPromise.resolve('我成功了哈');
console.log(pResolve, 'pResolve');
const pReject = testPromise.reject('我失败了哈');
console.log(pReject, 'pReject')
</script>
// 类中的静态方法没办法调用属性和方法
static resolve(value) {
return new testPromise(resolve => {
resolve(value);
});
};
static reject(err) {
return new testPromise((resolve, reject) => {
reject(err);
});
};
4. p.catch()
- 捕获 Promise 对象中的
reject传的值,如果你只要获取 reject 传的值,不需要获取resolve传的值,就不需要使用then方法
<script type="module">
testP.catch(err => {
console.log(err, 'catch 捕获错误');
});
</script>
catch(onRejected) {
return this.then(undefined, onRejected);
};
5. Promise.race()
- 函数返回一个
Promise对象,传的是一个数组 - race 是竞赛的意思,就是数组中的 promise 对象中最先执行完的promise对象,并返回那个promise结果的结果
<script type="module">
const MyP1 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP1');
// reject('MyErr');
}, 2000);
});
const MyP2 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP2');
}, 1000);
});
testPromise.race([MyP1, MyP2]).then(res => {
console.log(res, 'res111');
}, err => {
console.log(err, 'err222');
});
</script>
- 上述实例中:最先执行完的是 MyP2,打印的结果是MyP2 err111
static race(lists) {
let status = false
return new testPromise((resolve, reject) => {
lists.forEach(item => {
item.then(res => {
if(!status) {
resolve(res);
status = true;
}
}, err => {
if(!status) {
reject(err);
status = true;
}
})
})
})
};
6. Promise.allSettled()
-
函数返回一个
Promise对象,传的是一个数组 -
获取的结果如下:
<script type="module">
const MyP1 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP1');
// reject('MyErr');
}, 2000);
});
const MyP2 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP2');
}, 1000);
});
testPromise.allSettled([MyP1, MyP2]).then(res => {
console.log(res, '2222222');
});
</script>
static allSettled(lists) {
// let resArr = [];
let resArr = new Array(lists.length);
let num = 0
return new testPromise((resolve, reject) => {
lists.forEach((item, key) => {
const obj = {};
item.then(res => {
obj['status'] = 'fulfilled';
obj['value'] = res;
resArr[key] = obj;
num ++
if(num >= lists.length) {
console.log(resArr, 'resArr1');
resolve(resArr)
}
}, err => {
obj['status'] = 'rejected';
obj['reson'] = err;
resArr[key] = obj;
num ++
if(num >= lists.length) {
// 最后都是 resolve 出结果
resolve(resArr)
}
})
})
})
}
7. Promise.all()
- 可以同时调用多个异步请求,
res返回的是数组,如何请求中有一个报错,则 返回的是err,简而言之,就是promise.all()中发请求的数组有一个报错,则都不会返回结果,只会返回一个err的错误
<script type="module">
const MyP1 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP1');
// reject('MyErr');
}, 2000);
});
const MyP2 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP2');
}, 1000);
});
const MyP3 = new testPromise((resolve,reject) => {
setTimeout(()=> {
resolve('MyP3');
// reject('MyP3');
}, 2000);
});
MyPromise.all([MyP1, MyP2, MyP3]).then(res =>{
console.log(res, 'MyPromise all');
}, err => {
console.log(err, 'err');
});
</script>
static all(lists) {
return new testPromise((resolve, reject) => {
const resArr = new Array(lists.length);
let num = 0;
lists.forEach((item, key) => {
item.then(res => {
resArr[key] = res;
num++
if(num >= lists.length) {
resolve(resArr);
}
}, err => {
reject(err);
});
})
})
};
8. Promise.finally()
- finally 不接受任何参数
- finally 在 catch 或 then 执行完毕之后再执行的,如果请求发送成功和失败都要执行事件的话,可以写在finally中,避免重复书写
<script type="module">
testP.finally(() => {
console.log('myP 我被调用了');
});
</script>
finally(cb) {
this.then(cb, cb);
}