【前端笔记】手写Promise,跟着教学轻松理解Promise

Promise是ES6新增为了解决异步编程的一种实现方案,配合asyncawiat可以做到更加优雅的书写异步任务并且实现同步执行。Promise意为承诺,承诺会在未来某个时间返回操作的结果

Promise几个简单示例:

let p = new Promise((resolve, reject) => {
    
    
    console.log(1);
    setTimeout(() => {
    
    
        resolve('then');
    }, 3000);
});

let p1 = new Promise(); // TypeError: Promise resolver undefined is not a function

p.then(res => console.log(1)); // '1', 3s -> 'then'

这个实例可以得到Promise的以下特点

  • new Promise后会立即执行,并且接收一个必传函数作为参数

  • 接收的函数中有2个参数

  • 值需要使用then方法获取

let p2 = new Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
})
console.log('p2', p2); // { PromiseState: 'fulfilled', PromiseResult: '成功' }

let p3 = new Promise((resolve, reject) => {
    
    
    reject('失败')
    resolve('成功')
})
console.log('p3', p3); // { PromiseState: 'rejected', PromiseResult: '失败' }

let p4 = new Promise((resolve, reject) => {
    
    
    throw('报错'); // { PromiseState: 'rejected', PromiseResult: '失败' }
})
console.log('p4', p4);

这个实例可以得到Promise的以下特点

  • 有三种状态:初始pending,成功fullfilled,拒绝rejected,并且状态只能从pending转变为fulfilled或者rejected,不可逆
  • resolve将状态转变为fulfilledreject将状态转变为rejected
  • 一旦状态从pending转变为fulfilled或者rejected就不会再改变了

1、根据前面的总结定义好初始结构

// 定义promise的状态
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    // 接收一个函数作为参数
    constructor(executor) {
    
    
        // 初始状态为pending
        this.status = PENDING;
        // new Promise后立即执行,接收2个参数
        executor(resolve, reject);
    }
    // 获取结果的函数
    then() {
    
    }
}

根据第二个示例我们可以看到p3中抛出错误也是被rejected的,所以优化下结构:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        // 新增try-catch捕获错误,出错时将状态转变为rejected
+       try {
    
    
         	executor(resolve, reject);   
+       } catch (error) {
    
    
            reject(error);
+       }
    }
    then() {
    
    }
}

2、实现resolve、reject方法

在前面的示例中已经知道promise传入的函数接收2个参数,也就是resolvereject,他们的作用就是改变promise的状态。

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        try {
    
    
+           executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
+	resolve() {
    
    }
+   reject() {
    
    }
    then() {
    
    }
}

状态只能从pending转变为fullfilledrejected,并且不可逆:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        try {
    
    
            executor(this.resolve, this.reject);
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
	resolve() {
    
    
        // 状态为pending才改变状态
+       if (this.status === PENDING) {
    
    
+          this.status = FULLFILLED;
+       }
  	}
  	reject() {
    
    
        // 状态为pending才改变状态
+    	if (this.status === PENDING) {
    
    
+      		this.status = REJECTED;
+    	}
  	}
  	then() {
    
    }
}

根据示例可以看到调用resolvereject时可以传递参数,最后可以通过调用then获取结果。

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        // 保存结果,最终返回
+       this.value = null;
        try {
    
    
            executor(this.resolve, this.reject);
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
+	resolve(value) {
    
    
        // 状态为pending才改变状态
        if (this.status === PENDING) {
    
    
          	this.status = FULLFILLED;
+           this.value = value;
        }
  	}
+  	reject(reason) {
    
    
        // 状态为pending才改变状态
    	if (this.status === PENDING) {
    
    
      		this.status = REJECTED;
+           this.value = reason;
    	}
  	}
  	then() {
    
    }
}

3、实现then方法

then方法返回一个Promise。它最多需要两个参数:Promise的成功和失败情况的回调函数(失败情况的回调函数为可选)——MDN

// 接收两个参数
then(onFullfilled, onRejected) {
    
    
    // 返回一个Promise
    return new _Promise((resolve, reject) => {
    
    });
}

因为then方法返回了promise,而promise上又有then方法,所以可以链式调用,例如:

let p = new Promise((resolve, reject) => {
    
    
    resolve(1);
});
p.then(res => {
    
    
    console.log(res);
    return res += 1;
}).then(res => {
    
    
    console.log(res);
    return res *= res;
}).then(res => {
    
    
    console.log(res);
}); // 1,2,4

先看下原生方法的执行结果:

let p = new Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功

// 反过来
let p = new Promise((resolve, reject) => {
    
    
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

new Promise时接收2个参数,分别为将状态转变为fullfilledrejected的回调函数。而then方法也是接收2个参数,分别为promise的成功和失败情况的回调函数。所以根据结果可以知道then方法就是在根据promise的状态执行对应的方法

// 接收两个参数
then(onFullfilled, onRejected) {
    
    
    // 如果状态为fullfilled,调用成功回调并将resolve时带来的参数传入并执行
+   if (this.status === FULLFILLED) {
    
    
+       onFullfilled(this.value);
+   }
    // 如果状态为rejected,调用失败回调并将reject时带来的参数传入并执行
+   if (this.status === REJECTED) {
    
    
+       onRejected(this.value);
+   }
    // 返回一个Promise
    return new _Promise((resolve, reject) => {
    
    });
}

暂时基本功能都有了,进行一下测试:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
       	this.status = PENDING;
       	this.value = null;
        try {
    
    
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
         	this.reject(error);
        }
    }
	resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
          	this.status = FULLFILLED;
           	this.value = value;
        }
  	}

  	reject(reason) {
    
    
    	if (this.status === PENDING) {
    
    
      		this.status = REJECTED;
           	this.value = reason;
    	}
  	}

    then(onFullfilled, onRejected) {
    
    
      	if (this.status === FULLFILLED) {
    
    
           onFullfilled(this.value);
      	}

       	if (this.status === REJECTED) {
    
    
           onRejected(this.value);
       	}

        return new _Promise((resolve, reject) => {
    
    });
    }
}

// 测试代码
let p = new _Promise((resolve, reject) => {
    
    
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功
// 反过来
let p = new _Promise((resolve, reject) => {
    
    
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

和原生执行一样,成功!但是,忽略了一些细节,比如:

// 原生
let p = new Promise((resolve, reject) => {
    
    
    resolve('成功');
})
p.then(
    null, // 或undefined
    error => console.log(error)
); // 无输出无报错

// 自己实现的
let p = new _Promise(resolve => {
    
    
    resolve('成功');
});
p.then(
    null,
    error => console.log(error)
); // onFullfilled is not a function

因为我们在then方法中实现是直接执行传入的函数,当这个参数不是函数因为没有做处理,把不是函数的参数当做函数执行自然就会报错,所以在then函数中给参数加个处理

then(onFullfilled, onRejected) {
    
    
    // 判断如果传入的参数类型不为function,就给它赋值为一个函数
+   onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
+   onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

    if (this.status === FULLFILLED) {
    
    
       onFullfilled(this.value);
    }

    if (this.status === REJECTED) {
    
    
       onRejected(this.value);
    }

    return new _Promise((resolve, reject) => {
    
    });
}

修改后再次执行之前的代码,发现就没有报错了

4、实现异步

到目前为止,代码里可以看到没有任何的特殊的东西,也就是说代码会正常按顺序同步执行。但是实际上不可能是都按照顺序同步执行的。众所周知JavaScript有个事件循环机制,将事件分为了同步任务异步任务两大类,接下来就要对异步任务进行处理,为什么呢?举个例子:

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    
    
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

// 应用到自己实现的上
console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,4,3

在MDN有说明,promise的操作会被视为异步执行,所有的promise都是异步的,并且和setTimeout(action, 10)特别相似。那么我们就用``setTimeout`来模拟异步。

then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

    if (this.status === FULLFILLED) {
    
    
+       setTimeout(() => {
    
    
           	onFullfilled(this.value); 
+       });
    }

    if (this.status === REJECTED) {
    
    
+       setTimeout(() => {
    
    
			onRejected(this.value);
+       });
    }

    return new _Promise((resolve, reject) => {
    
    });
}

重新执行一下之前的代码,发现输出顺序就已经正确输出1,2,3,4了

5、处理收集回调

根据上一步骤可以知道promise和它的操作都是异步的。那么有怎么一种情况,我在promise里也写异步事件会怎么样呢。如果了解了事件循环的话应该会知道,这里暂且提一嘴

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);

事件循环解释一下上面代码执行的过程:

  1. 执行同步任务console.log(1);,输出"1"
  2. new Promise()立即执行,执行同步任务console.log(2);并输出"2",遇见异步任务setTimeout加入到宏任务队列(异步任务分为宏任务和微任务,promise的回调为微任务)
  3. 遇到p.then(),将其回调加入到微任务队列
  4. 执行同步任务console.log(3);并输出"3"
  5. 主线程执行栈清空,去寻找异步任务执行,发现同时存在宏任务和微任务,先执行微任务
  6. 执行微任务then回调,此时promise状态为pending不执行
  7. 执行同步任务console.log(4);并输出"4"
  8. 微任务执行完毕执行宏任务,执行同步任务console.log(4);并输出"4"
  9. 调用resolve(5);,此时promise状态改变,执行对应的回调,输出"5"

所以输出为:1,2,3,4,5

去_promise`上去,查看执行结果:

console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

发现执行结果少输出一个5,而5是执行then的回调打印的,那么可以猜测是then没有被执行。而我们的then中执行是进行了状态判断的,也就是说只有当promise状态为FULLFILLED或者REJECTED时才会执行。打印一下执行时的status看看是不是它的问题

console.log(1);
let p = new _Promise((resolve, reject) => {
    
    
    console.log(2);
    setTimeout(() => {
    
    
        console.log(4);
        console.log(p.status);
        resolve(5);
        console.log(p.status);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4,pending,fullfilled

继续用事件循环来梳理下执行过程:

  1. 执行同步任务console.log(1),输出"1"
  2. new Promise()立即执行,执行同步任务console.log(2);,输出"2"
  3. 遇到异步任务setTimeout加入到宏任务队列
  4. 遇到异步任务then回调,加入到微任务队列
  5. 执行同步任务console.log(3);,并输出"3"
  6. 主线程执行栈清空,去寻找异步任务执行,发现同时存在宏任务和微任务,先执行微任务
  7. 执行微任务then回调,此时promise状态为pending没有执行结果
  8. 微任务执行完毕执行宏任务,执行同步任务console.log(4);并输出"4"
  9. 执行console.log(p.status);,输出"pending"
  10. 执行resolve(5);promise状态改变为fullfilled
  11. 执行console.log(p.status);,输出"fullfilled"

观察执行过程可以发现,当promise的状态为pending时,自己实现的then方法中是没有做对应处理的。可能这就是导致了没有执行的问题。那么当状态为pending时我们应该做什么呢?

then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
+   if (this.status === PENDING) {
    
    
        // TODO: 状态为pending时应该做什么
+   }

    if (this.status === FULLFILLED) {
    
    
       	setTimeout(() => {
    
    
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
    
    
       	setTimeout(() => {
    
    
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {
    
    });
}

这里继续以执行顺序来理解。then函数是同步执行的,而获得结果是需要调用resolve或者reject的。那么我们怎么样才能保证then方法在获取到结果后才执行呢?解决办法就是收集回调`。

promise的状态为pending时,我们先将回调收集起来,等到执行resolve或者reject时,将对应的回调取出来一并执行。

1、创建数组收集回调,毕竟回调可能有多个
class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        // 收集成功的回调
+       this.fullfilledCallbacks = [];
        // 收集失败的回调
+       this.rejectedCallbacks = [];

        try {
    
    
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
          	this.reject(error);
        }
	}
}
2、在then方法中收集回调
then(onFullfilled, onRejected) {
    
    
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
    // 状态为pending时收集依赖
   	if (this.status === PENDING) {
    
    
+       this.fullfilledCallbacks.push(onFullfilled);
+       this.rejectedCallbacks.push(onRejected);
   	}

    if (this.status === FULLFILLED) {
    
    
       	setTimeout(() => {
    
    
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
    
    
       	setTimeout(() => {
    
    
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {
    
    });
}
3、resolve和reject方法中执行回调

在执行resolve()或者reject()时,会遍历保存的对应的回调数组(在执行then时保存的),并将参数传入执行。

resolve(value) {
    
    
    if (this.status === PENDING) {
    
    
        this.status = FULLFILLED;
        this.value = value;
        // 执行收集的回调
+       this.fullfilledCallbacks.forEach(callback => callback(value));
    }
}

reject(reason) {
    
    
    if (this.status === PENDING) {
    
    
        this.status = REJECTED;
        this.value = reason;
        // 执行收集的回调
+       this.rejectedCallbacks.forEach(callback => callback(reason));
    }
}

整体代码如下:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
    
    
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
          	this.reject(error);
        }
	}
    resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
            this.status = FULLFILLED;
            this.value = value;
            this.fullfilledCallbacks.forEach(callback => callback(value));
        }
    }

    reject(reason) {
    
    
        if (this.status === PENDING) {
    
    
            this.status = REJECTED;
            this.value = reason;
            this.rejectedCallbacks.forEach(callback => callback(reason));
        }
    }
    then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        if (this.status === PENDING) {
    
    
            this.fullfilledCallbacks.push(onFullfilled);
            this.rejectedCallbacks.push(onRejected);
        }

        if (this.status === FULLFILLED) {
    
    
            setTimeout(() => {
    
    
                onFullfilled(this.value); 
            });
        }

        if (this.status === REJECTED) {
    
    
            setTimeout(() => {
    
    
                onRejected(this.value);
            });
        }

        return new _Promise((resolve, reject) => {
    
    });
    }
}

再次执行之前测试的代码,发现then函数的回调触发了。但是细心点还是可以发现,在打印promise状态之后同步执行了resolve并触发了回调,这明显是不对的,我们期望的是resolvereject是异步执行的。所以这里使用setTimeout来模拟异步

resolve(value) {
    
    
    if (this.status === PENDING) {
    
    
+       setTimeout(() => {
    
    
           	this.status = FULLFILLED;
        	this.value = value;
        	this.fullfilledCallbacks.forEach(callback => callback(value)); 
+       });
    }
}

reject(reason) {
    
    
    if (this.status === PENDING) {
    
    
+       setTimeout(() => {
    
    
            this.status = REJECTED;
        	this.value = reason;
        	this.rejectedCallbacks.forEach(callback => callback(reason));
+       });
    }
}

再次测试输出结果,就会发现输出和原生一致了

4、测试多次执行then方法

原生promise可以多次调用then,同样的也给自己实现的进行一下测试

// 原生
const p = new Promise((resolve, reject) => {
    
    
    setTimeout(() => {
    
    
        resolve('success')
    }, 2000);
})
p.then(value => {
    
    
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

// 自己实现的
const p = new _Promise((resolve, reject) => {
    
    
    setTimeout(() => {
    
    
        resolve('success')
    }, 2000);
})
p.then(value => {
    
    
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    
    
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

没有问题,基本大功告成!剩下最后的promise链式调用

6、实现链式调用

首先用一个简单示例解释一下什么是链式调用

class Person {
    
    
    constructor() {
    
    
        this.name = '';
    }
    setName(name) {
    
    
        this.name = name;
        return this;
    }
    sayHello() {
    
    
        console.log(`hello,我叫${
      
      this.name}`);
        return this;
    }
}
// 使用
let p = new Person();
p.setName('哈哈哈').sayHello(); // hello,我叫哈哈哈

链式调用的核心就是上面的return this。当我们调用p.setName()时会返回自身实例,而实例上存在setNamesayHello两个方法,所以就能一直.setName()或者.sayHello()调用下去。

回到我们的then方法会发现在之前已经提前返回了一个new _Promise()。因为Promise要求then返回一个promise。所以这就是then方法能够链式调用的原因。还不明白可以认真立即上面这段话。

扩展:在以前使用Ajax发送请求时也会存在then回调,并且会出现因为then的无限嵌套回调而出现的回调地狱,解决办法就是使用基于Promise的asyncawait语法糖

在原生Promise中我们是这样使用链式调用的:

let p = new Promise((resolve, reject) => {
    
    
    resolve(1);
});
p.then(res => {
    
    
    console.log(res);
    return res + 1;
}).then(res => {
    
    
    console.log(res);
});
// 1,2

将同样的代码运用到自己实现的_Promise上后会发现有问题,因为我们then方法还没有完善,返回的_Promise里什么都没有。那么接下来就完善这个then方法。

1、首先将内容移动到返回的Promise中去
then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        return new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(onFullfilled);
                this.rejectedCallbacks.push(onRejected);
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    onFullfilled(this.value); 
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    onRejected(this.value);
                });
            }
        });
    }
}
2、封装处理Promise返回内容的函数
function resolvePromise(promise2, x, resolve, reject) {
    
    
    // 不能返回自身
    if (x === promise2) {
    
    
        throw Error('不能返回自身');
    }
    // 如果是Promise
    if (x instanceof _Promise) {
    
    
        // 状态为pending
        if (x.status === PENDING) {
    
    
            // 收集回调等待执行
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        // 状态为fullfilled,调用resolve执行
        } else if (x.status === FULLFILLED) {
    
    
            resolve(x.value);
        // 状态为rejected,调用reject执行
        } else {
    
    
            reject(x.value);
        }
    // 如果是thenable对象(具有then属性)
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    
    
        let then = null;
        try {
    
    
            // 有then属性,赋值
            then = x.then;
        } catch (error) {
    
    
            // 获取不到then报错就调用reject
            reject(error);
        }
        // 如果then是个函数,就以promise相同方式调用
        if (typeof then === 'function') {
    
    
			let called = false; // 避免多次调用
            try {
    
    
                then.call(
                    x,
                    res => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
    
    
                        // 防止多次调用
                         if (called) {
    
    
                            return;
                        }
                        called = true;
                        // 出错就调用reject
                        reject(error);
                    }
                )
            } catch (error) {
    
    
                // 防止多次调用
                if (called) {
    
    
                    return;
                }
                called = true;
                // 出错就调用reject
                reject(error);
            }
        } else {
    
    
            // 否则就是个正常值,执行调用resolve
            resolve(x);
        }
    // 否则直接调用resolve
    } else {
    
    
        resolve(x);
    }
}
3、修改then方法中的逻辑
then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }
        let promise2 = new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }
	});
    return promise2;
}

接下来进行测试:(随便找的一个例子)

// 原生
const p1 = new Promise((resolve, reject) => {
    
    
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    
    
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    
    
    console.log(res);
    return new Promise((resolve, reject) => {
    
    
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    
    
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => {
    
     }, err => {
    
    
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

// 自己实现的_Promise
const p1 = new _Promise((resolve, reject) => {
    
    
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    
    
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    
    
    console.log(res);
    return new _Promise((resolve, reject) => {
    
    
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    
    
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => {
    
     }, err => {
    
    
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

至此,已经根据原生实现了一个自己的Promise

完整代码:
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
    
    
    if (x === promise2) {
    
    
        throw Error('不能返回自身');
    }
    if (x instanceof _Promise) {
    
    
        if (x.status === PENDING) {
    
    
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        } else if (x.status === FULLFILLED) {
    
    
            resolve(x.value);
        } else {
    
    
            reject(x.value);
        }
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    
    
        let then = null;
        try {
    
    
            then = x.then;
        } catch (error) {
    
    
            reject(error);
        }
        if (typeof then === 'function') {
    
    
            let called = false;
            try {
    
    
                then.call(
                    x,
                    res => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
    
    
                        if (called) {
    
    
                            return;
                        }
                        called = true;
                        reject(error);
                    }
                )
            } catch (error) {
    
    
                if (called) {
    
    
                    return;
                }
                called = true;
                reject(error);
            }
        } else {
    
    
            resolve(x);
        }
    } else {
    
    
        resolve(x);
    }
}

class _Promise {
    
    
    constructor(executor) {
    
    
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
    
    
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
    
    
            this.reject(error);
        }
    }
    resolve(value) {
    
    
        if (this.status === PENDING) {
    
    
            setTimeout(() => {
    
    
                this.status = FULLFILLED;
                this.value = value;
                this.fullfilledCallbacks.forEach(callback => callback(value));
            })
        }
    }

    reject(reason) {
    
    
        if (this.status === PENDING) {
    
    
            setTimeout(() => {
    
    
                this.status = REJECTED;
                this.value = reason;
                this.rejectedCallbacks.forEach(callback => callback(reason));
            })

        }
    }

    then(onFullfilled, onRejected) {
    
    
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => {
    
     throw Error(error) }

        let promise2 = new _Promise((resolve, reject) => {
    
    
            if (this.status === PENDING) {
    
    
                this.fullfilledCallbacks.push(() => {
    
    
                    try {
    
    
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
    
    
                    try {
    
    
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
    
    
                setTimeout(() => {
    
    
                    try {
    
    
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }
        });
        return promise2;
    }
}

本文参考:https://juejin.cn/post/7043758954496655397

更详细、更完整代码(包含注释)可以参考以上连接

猜你喜欢

转载自blog.csdn.net/qq_43398736/article/details/126917836