这个是尚硅谷promise课程中手写promise的笔记。
1. 基本结构
function Promise(executor){
// 执行器函数会被立即同步调用
exectutor()
}
Promise.prototype.then = function(onResovled, onRejected){
}
2. resolve和reject的结构
function Promise(executor){
// exectutor有两个函数参数
exectutor(resolve, reject)
// exectuor两个函数参数的定义
function resolve(data){
}
function reject(data){
}
}
Promise.prototype.then = function(onResovled, onRejected){
}
3.resolve/reject代码实现
resolve函数至少要做两件事: (1)改变promise的状态;(2)设置promise的结果。reject也是同样的
function Promise(executor){
this.PromiseState = 'pending'
this.PromiseResult = null
const self = this
funcion resolve(data){
self.PromiseState = 'fulfilled'
self.PromiseResult = data
// 如果按照下面这样写,当调用resolve(xx)时,this实质是window对象。
// this.PromiseState = 'fulfilled'
// this.PromiseResult = data
}
function reject(data){
self.PromiseState = 'rejected'
self.PromiseResult = data
}
...
}
此时可以测试一下新建一个promise,并进行reslove、reject的调用。
function Promise(executer) {
this.PromiseState = 'pending'
this.PromiseResult = null
const self = this
executer(resolve, reject);
function resolve(data) {
self.PromiseState = 'fulfilled'
self.PromiseResult = data
}
function reject(data) {
self.PromiseState = 'rejected'
self.PromiseResult = data
}
}
const p = new Promise((resolve, reject) => {
resolve(2)
})
console.log(p)
4. 通过throw改变promise状态
改变promise状态有三种方法,(1)resolve, (2)reject(3)throw an execption。 前面已经通过(1)(2)改变了promise状态,这里则实现(3)。
try{
executer(resolve, reject)
}catch(e){
self.PromiseState = 'rejected'
self.PromiseResult = e
}
5.令promise状态只能改变一次
只需要在每次改变状态前先去check状态是否已经被改变即可。
if(selft.PromiseState !== 'pending')
return
6. 实现then方法中执行callback
Promise.prototype.then = function(onResolved, onRejected) {
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
}
7 异步任务回调的执行
目前如果我们需要执行异步操作,then方法是无法执行的。例如:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
},1000)
})
// 现在是同步代码,当p执行then时,resolve还未执行,导致promise状态还是pending状态
// 而在前面的代码中,promise是pending状态时,then中的callback都是不会执行的。
p.then(res => console.log(res))
所以我们需要:
(1)在then中,需要判定是否是pending状态,如果是pending状态,我们需要有一些对应的处理。
Promise.prototype.then = function(onResolved, onRejected){
...
if(this.PromiseState === 'pending') {
// do something...
}
}
(2)在resolve和reject函数中,我们需要调用then中的callback
resolve() {
//call onResolved
}
reject() {
// call onRejected
}
为了使我们能够在resolve和reject函数中调用到then中的callback,我们需要把callback存储在对象上。
function Promise(executor){
....
// 用来保存then中传的两个callback,帮助实现异步调用
this. callback = {}
function resolve(data){
....
// 调用callback
if(self.callback.onResolved){
self.callback.onResolved(data)
}
}
function reject(data){
...
// 调用callback
if(self.callback.onRejected){
self.callback.onRejected(data)
}
}
}
Promise.prototype.then = function(onResolved, onRejected){
...
if(this.PromiseState === 'pending'){
// 为callback赋值
this.callback = {
onResovled,
onRejected
}
}
}
8 指定多个回调的实现
目前当我们指定多个回调时,下面的会覆盖掉上面的。
p.then(res => {
console.log(res)
},
err => {
console.log(err)
})
// 这里指定的回调会把上面指定的回调覆盖掉
p.then(res => {
alert(res)
},
err => {
alert(err)
})
所以我们需要修改保存回调的方式,让其能够保存多个回调,也就是说 需要把实例上存储的callback改为数组的形式
this.callback = []
在then中
if(this.PromiseState === 'pending'){
this.callback.push({
onResolved,
onRejected
})
}
当改变状态调用时
self.callback.forEach(cb => {
cb.onResolved(data)
})
9 同步方式下then的返回结果实现
then的返回值应该是一个Promise. 在resolve时,如果返回的是非Promise,则返回的是Promise状态为fulfilled,PromiseResult根据resolve callback返回结果而定。
如果返回的是Promise,则状态和结果根据这个Promise而定。
Promise.prototype.then = function(onResvoled, onRejected){
return new Promise((resolve, reject) => {
if(this.PromiseState === 'fulfilled'){
try{
let result = onResolved(this.PromiseResult)
// 这里的r和e是在使用时then中return的新Promise的resolve和reject的参数
if(result instanceof Promise){
result.then(r => resolve(r), e => reject(e))
}else{
resolve(result)
}
}catch(e){
reject(e)
}
}
.....
})
}