手写promise
2020-09-04 本文已影响0人
小宇cool
1. 为什么需要Promise?
我们通常都会说为了解决回调地狱,大家都知道在做前端开发时,最让人头痛的就是处理异步请求, 在请求的成功的回调函数里面进行写函数, 长此以往形成了回调地狱
function load(){
function init(res,callback){
callback(res + 10)
}
function redner(res2,callback){
callback(res2+10)
}
setTimeout((res) =>{
init(res,(res2) =>{
redner(res2,(res3)=>{
console.log(res3);// 30
})
})
}, 2000, 10);
}
load()
上面的代码就是一个回调地狱,存在着多层嵌套的的问题, 如果层级还多一点, 那么代码会变得极其难以维护,
1.1 promise的简单使用
上面的代码通过如果使用promise就会变得简洁清晰很多.
function load() {
return new Promise((reslove, reject) => {
setTimeout((res) => {
reslove(res)
}, 2000, 10);
})
}
load()
.then(res => {
return res + 10
})
.then(res => {
return res + 10
})
.then(res =>{
console.log(res);// 30
})
2. 怎么实现一个promise?
Promise是一个类,类中需要传入一个executor执行器, 执行器会默认执行,就像下面这样打印出1
new Promise(()=>{
console.log(1)
})
- 首先介绍Promise的三种状态
- Pending 创建Promise对象的初始状态.
- Fulfilled 成功的状态.
- Rejected 失败时的状态.
-
promise的状态一旦从pending状态改变为成功或失败就不能在改变
-
每个promise实例都有一个then方法, 分别是成功和失败的回调;
-
promise内部会提供两个方法, 注意不是原型上的,这两个方法是给用户的,用来改变promise状态.
了解了上面的基本几点后, 我们可以写成一个基本的promise;
1. 同步promise
class _Promise{
static PENGIND = 'PENDING';// 准备状态常量
static FULFILLED = 'FULFILLED';// 成功状态
static REJECTED = 'REJECTED';//拒绝状态
constructor(executor){
this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
this.value = undefined; // 保存改变状态时传递的值
// //用于class 默认使用严格模式, 所有需要手动绑定this
const resolve = _Promise.reslove.bind(this)
const reject = _Promise.reject.bind(this);
try {
executor(resolve,reject)// 传入两个方法
} catch (error) {// 当executor报错时把 错误值传递给拒绝方法
reject(error)
}
}
reslove(value){
// 当状态为等待状态时改变promise实例状态为 成功
if(this.status === _Promise.PENGIND){
this.status = _Promise.FULFILLED
this.value = value;
}
}
reject(reason){
// 当状态为等待状态时改变promise实例状态为拒绝
if(this.status === _Promise.PENGIND){
this.status = _Promise.REJECTED
this.value = reason;
}
}
then(onfulfilled=()=>{},onRejected=()=>{}){// 给then方法内的两个回调函数添加默认值
// 如果传递参数的类型不是函数, 就抛出一个错误
if(typeof onRejected !== "function" ||typeof onRejected !== "function"){
throw new Error('The argument type must be a function')
}
//当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
if(this.status === _Promise.FULFILLED){
onfulfilled(this.value)
}
if(this.status === _Promise.REJECTED){
onRejected(this.value)
}
}
}
2. 异步promise
promise 状态只能在 reslove状态 或者 reject的时候改变, 同步代码执行到then回调的时候promise状态是pending,明显是不符合我们的期望的.这里我们可以使用发布订阅模式,发布订阅模式简单来说就是我们将现在要做的事情.放到某个时间点在进行执行.
思路:我们可以在实例对象上定义两个数组用来保存then调用时的回调函数, 当状态改变方法调用时, 我们从实例对象上拿到这两个数组里的回调函数进行遍历, 对其进行调用同时传递参数
class _Promise{
static PENGIND = 'PENDING';// 准备状态常量
static FULFILLED = 'FULFILLED';// 成功状态
static REJECTED = 'REJECTED';//拒绝状态
constructor(executor){
this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
this.value = undefined; // 保存状态成功时传递的值
this.reason = undefined; // 保存状态拒绝时传递的值
this.onResloveCallbackS = []; // 保存状态成功的回调函数
this.onRejectEdCallbackS = []; //保存状态拒绝的回调函数
const resolve = _Promise.reslove.bind(this)// 将实例上的静态方法的内部this绑定到实例对象
const reject = _Promise.reject.bind(this);
try {
executor(resolve,reject)// 传入两个方法
} catch (error) {// 当executor报错时把 错误值传递给解决方法
reject(error)
}
}
reslove(value){
// 当状态为等待状态时改变promise实例状态为 成功
if(this.status === _Promise.PENGIND){
this.status = _Promise.FULFILLED
this.value = value;
// 异步执行then方法里的回调函数
setTimeout(() => {
this.onResloveCallbackS.map(callback => callback.onFulfilled(this.value))
});
}
}
reject(reason){
// 当状态为等待状态时改变promise实例状态为拒绝
if(this.status === _Promise.PENGIND){
this.status = _Promise.REJECTED
this.reason = reason;
// 异步执行then方法里的回调函数,
setTimeout(()=>{
// 把then里面的回调函数进行执行并传参
this.onResloveCallbackS.map(callback => callback.onRejected(this.reason))
})
}
}
then(onFulfilled=()=>{},onRejected=()=>{}){// 给then方法内的两个回调函数添加默认值
// 如果传递参数的类型不是函数, 就抛出一个错误
if(typeof onRejected !== "function" ||typeof onRejected !== "function"){
throw new Error('The argument type must be a function')
}
//当状态为准备时, 将then内部的函数放在状态改变时执行
if(this.status === _Promise.PENGIND){
this.onResloveCallbackS.push({
onFulfilled: value => {// value 会接受promise状态改变时传递的值
try {// 对异步状态时进行trycatch 捕获错误
onFulfilled(value)// 执行成功状态时方法
} catch (error) {
onRejected(error)// 将错误抛给onRejected 方法处理
}
}
})
this.onRejectEdCallbackS.push({
onRejected: reason =>{
try {
onRejected(reason)
} catch (error) {
onRejected(error)
}
}
})
}
//当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
if(this.status === _Promise.FULFILLED){
// 异步执行 then方法里的回调函数
setTimeout(() => {
try {// 捕获then回调函数执行是发生时的错误
onFulfilled(this.value);
} catch (error) {
onRejected(error)
}
});
}
if(this.status === _Promise.REJECTED){
setTimeout(() => {
try {
onRejected(this.reason)
} catch (error) {
onRejected(error)
}
});
}
}
}
3. 链式promise
我们可以给then方法返回一个新promise,并将then返回的数据传递给新promise, 当发生错误时, 传递给reslove, 当发生异常时,我们通过trycatch 捕获并传递给 reject
class _Promise {
static PENGIND = 'PENDING';// 准备状态常量
static FULFILLED = 'FULFILLED';// 成功状态
static REJECTED = 'REJECTED';//拒绝状态
constructor(executor) {
this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
this.value = undefined; // 保存状态成功时传递的值
this.reason = undefined; // 保存状态拒绝时传递的值
this.onResloveCallbackS = []; // 保存状态成功的回调函数
this.onRejectEdCallbackS = []; //保存状态拒绝的回调函数
//用于class 默认使用严格模式, 所有需要手动绑定this
const resolve = this.reslove.bind(this)
const reject = this.reject.bind(this);
try {
executor(resolve, reject)// 传入两个方法
} catch (error) {// 当executor报错时把 错误值传递给解决方法
reject(error)
}
}
reslove(value) {
// 当状态为等待状态时改变promise实例状态为 成功
if (this.status === _Promise.PENGIND) {
this.status = _Promise.FULFILLED
this.value = value;
// 异步执行then方法里的成功方法
setTimeout(() => {
this.onResloveCallbackS.map(callback => callback.onFulfilled(this.value))
});
}
}
reject(reason) {
// 当状态为等待状态时改变promise实例状态为拒绝
if (this.status === _Promise.PENGIND) {
this.status = _Promise.REJECTED
this.reason = reason;
// 异步执行then方法里的拒绝方法,
setTimeout(() => {
// 把then里面的回调函数进行执行并传参
this.onRejectEdCallbackS.map(callback => callback.onRejected(this.reason))
})
}
}
// 默认返回 实例对象上的用于保存状态所对应的值, 实现then方法的穿透
then(onFulfilled = () => this.value, onRejected = () => this.reason) {// 给then方法内的两个回调函数添加默认值
// 如果传递参数的类型不是函数, 就抛出一个错误
if (typeof onRejected !== "function" || typeof onRejected !== "function") {
throw new Error('The argument type must be a function')
}
let promise = new _Promise((reslove, reject) => {
//当状态为准备时, 将then内部的函数放在状态改变时执行
if (this.status === _Promise.PENGIND) {
this.onResloveCallbackS.push({
onFulfilled: value => {// value 会接受promise状态改变时传递的值
this.parse(promise,onFulfilled(value), reslove, reject)
}
})
this.onRejectEdCallbackS.push({
onRejected: reason => {
this.parse(promise,onRejected(reason), reslove, reject);
}
})
}
//当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
if (this.status === _Promise.FULFILLED) {
// 异步执行 then方法里的回调函数
setTimeout(() => {
this.parse(promise,onFulfilled(this.value), reslove, reject);
});
}
if (this.status === _Promise.REJECTED) {
this.parse(promise,onFulfilled(this.reason), reslove, reject);
}
})
return promise // 返回新的promise
}
// 解析promise 状态
parse(promise,result,reslove,reject){//
if(promise === result){ // 对then 返回的值进行约束,不能返回自己的promise, 否者抛出错误
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
try {// 状态执行时进行trycatch 捕获错误
if(result instanceof _Promise){// 如果状态改变执行方法返回的是一个promise
result.then( res => reslove(res), reason => reject(reason))
// 因为res和rej 方法默认会执行,并传递参数, 所以我们可以简写成这种形式
// result.then(reslove,reject)
}else{
reslove(result)// 改状态成功时返回的参数传递给下一个promise的reslove方法
}
} catch (error) {
//当当一个promise发生错误时, 将错误抛给下一个promise的reject方法
reject(error)// 将错误抛给onRejected 方法处理
}
}
}
4. 实现静态reslove, reject方法
static reslove(value){
return new _Promise((reslove,reject) =>{// 返回一个新的的promise
if(value instanceof _Promise){//判断传递的是否为一个promise
value.then(reslove,reject)// 传递promise状态值
}else{
reslove(value)
}
})
}
static reject(reason){
return new _Promise((reslove,reject) =>{
reject(reason)
})
}
5. 实现promise.all方法
static All(promises){
const values = [];// 用来保存 promise状态成功时定义的值
return new _Promise((reslove,reject) =>{
promises.forEach(promise => {
promise.then(
value =>{
values.push(value);
// 如果所有promise对应的状态都为成功,即他们的数组长度相同,
if(values.length === promises.length){
reslove(values) //调用成功状态执行的回调函数 并传值
}
},
reason => {
reject(reason)// 调用拒绝状态执行的回调函数 并传值
}
)
});
})
}