# Promise A+

# 简易实现

//定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function MyPromise(executor){
    const self = this;          // 缓存当前promise实例
    self.state = PENDING;       // 默认状态
    self.value = null;          // 成功的值
    self.error = null;          // 失败的值
    self.onFulfilled = null;    // 保存then中的回调
    self.onRejected = null;     // 保存catch中的回调

    const resolve = (value) => {
        if(self.state == PENDING){
            setTimeout(() => {
                self.state = FULFILLED;
                self.value = value;
                self.onFulfilled(self.value)
            })
        }
    }
    
    const reject = (error) => {
        if(self.state == PENDING){
            setTimeout(() => {
                self.state = REJECTED;
                self.error = error;
                self.onRejected(self.value)
            })
        }
    }

    // 如果executor执行报错,直接执行reject
    try{
        executor(resolve, reject)
    }catch(err){
        reject(err)
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected){
    if(this.state == PENDING){
        this.onFulfilled = onFulfilled
        this.onRejected = onRejected
    }
    else if(this.state == FULFILLED){
        onFulfilled(this.value)
    }
    else{
        onRejected(this.error)
    }
    return this;
}

//执行promise
new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    }, 1000)
}).then(res => {
    console.log(res) // 1
})

可以看到,Promise 的本质是一个有限状态机,存在三种状态:

  • PENDING(等待)
  • FULFILLED(成功)
  • REJECTED(失败)

对于 Promise 而言,状态的改变不可逆,即由等待态变为其他的状态后,就无法再改变了。

# 回调数组

首先只能执行一个回调函数,对于多个回调的绑定就无能为力,比如下面这样:

let promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    })
});

let x1 = promise.then(res => {
    console.log("第一次展示", res);    
})

let x2 = promise.then(res => {
    console.log("第二次展示", res);    
})

// 只会执行最后一个, 前面的会被覆盖
let x3 = promise.then(res => {
    console.log("第三次展示", res);    
})

这里我绑定了三个回调,想要在 resolve() 之后一起执行,那怎么办呢?

需要将 onFulfilledonRejected 改为数组,调用 resolve 时将其中的方法拿出来一一执行即可。

self.onFulfilledCallback = [];
self.onRejectedCallback = [];
MyPromise.prototype.then = function(onFulfilled, onRejected){
    // 判断then的参数是否为函数类型,不是则赋予默认值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error }

    if(this.state == PENDING){
        this.onFulfilledCallbacks.push(onFulfilled);
        this.onRejectedCallbacks.push(onRejected);
    }
    else if(this.state == FULFILLED){
        onFulfilled(this.value)
    }
    else{
        onRejected(this.error)
    }
    return this;
}

接下来将 resolvereject 方法中执行回调的部分进行修改

遍历调用所有方法:

// resolve
self.onFulfilledCallbacks.map(cd => cd(self.value));
// reject
self.onRejectedCallbacks.map(cd => cd(self.error));

# 链式调用

我们采用目前的代码来进行测试:

const promise = (name) => {
    return new MyPromise((resolve, reject) => {
        resolve(name)
    })
}

promise('1111').then(res => {
    console.log(res)
    return promise('22222')
}).then(res => {
    console.log(res)
})
// 1111
// 1111

咦?怎么打印了两个 1111,第二次不是 2222 吗?

问题出在这:

MyPromise.prototype.then = function(onFulfilled, onRejected) {
  //...
  return this;
}

这么写每次返回的都是第一个 Promise。then 函数当中返回的第二个 Promise 直接被无视了!

说明 then 当中的实现还需要改进, 我们现在需要对 then 中返回值重视起来。

先对返回Promise的情况进行处理:

function resolvePromise(bridgePromise, x, resolve, reject) {
  //如果x是一个promise
  if (x instanceof MyPromise) {
    // 拆解这个 promise ,直到返回值不为 promise 为止
    if (x.status === PENDING) {
      x.then(y => {
        resolvePromise(bridgePromise, y, resolve, reject);
      }, error => {
        reject(error);
      });
    } else {
      x.then(resolve, reject);
    }
  } else {
    // 非 Promise 的话直接 resolve 即可
    resolve(x);
  }
}

然后,对所有状态进行处理

if(this.state == PENDING){
    return bridgePromise = new MyPromise((resolve, reject) => {
        // 避免传入错误值
        self.onFulfilledCallbacks.push((value) => {
            try{
                const x = onFulfilled(value)
                resolvePromise(bridgePromise, x, resolve, reject);
            }catch(err){
                reject(err)
            }
        })
        self.onRejectedCallbacks.push((err) => {
            try{
                const x = onRejected(err)
                resolvePromise(bridgePromise, x, resolve, reject);
            }catch(err){
                reject(err)
            }
        })
    })
}
else if(this.state == FULFILLED){
    return bridgePromise = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            try{
                const x = onFulfilled(self.value)
                resolvePromise(bridgePromise, x, resolve, reject);
            }catch(err){
                reject(err)
            }
        })
    })
}
else{
    return bridgePromise = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            try{
                const x = onRejected(self.error)
                resolvePromise(bridgePromise, x, resolve, reject);
            }catch(err){
                reject(err)
            }
        })
    })
}

# 错误捕获

MyPromise.prototype.catch = function(onRejected) {
    return this.then(null, onRejected)
}

// then 的实现中
onRejected = typeof onRejected === "function" ? onRejected : error => { throw error };

对,就是这么几行,catch 原本就是 then 方法的语法糖。

到这里就ok了, 接下来把完整代码贴出来

# Promise/A+

//定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function MyPromise(executor){
    const self = this;          // 缓存当前promise实例
    self.state = PENDING;       // 默认状态
    self.value = null;          // 成功的值
    self.error = null;          // 失败的值
    self.onFulfilledCallbacks = [];    // 保存then中的回调
    self.onRejectedCallbacks = [];     // 保存catch中的回调

    const resolve = (value) => {
        if(self.state == PENDING){
            setTimeout(() => {
                self.state = FULFILLED;
                self.value = value;
                self.onFulfilledCallbacks.map(cd => cd(self.value));
            })
        }
    }
    const reject = (error) => {
        if(self.state == PENDING){
            setTimeout(() => {
                self.state = REJECTED;
                self.error = error;
                self.onRejectedCallbacks.map(cd => cd(self.error));
            })
        }
    }

    // 如果executor执行报错,直接执行reject
    try{
        executor(resolve, reject)
    }catch(err){
        reject(err)
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected){
    let self = this,
        bridgePromise;

    // 判断then的参数是否为函数类型,不是则赋予默认值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error }

    function resolvePromise(bridgePromise, x, resolve, reject) {
        // 如果x是一个promise
        if(x instanceof MyPromise){
            if(x.state === PENDING){
                x.then(y => {
                    resolvePromise(bridgePromise, y, resolve, reject)
                }), err => {
                    reject(err)
                }
            }else{
                x.then(resolve, reject)
            }
        }else{
            // 非 Promise 的话直接 resolve 即可
            resolve(x)
        }
    }

    if(this.state == PENDING){
        return bridgePromise = new MyPromise((resolve, reject) => {
            // 避免传入错误值
            self.onFulfilledCallbacks.push((value) => {
                try{
                    const x = onFulfilled(value)
                    resolvePromise(bridgePromise, x, resolve, reject);
                }catch(err){
                    reject(err)
                }
            })
            self.onRejectedCallbacks.push((err) => {
                try{
                    const x = onRejected(err)
                    resolvePromise(bridgePromise, x, resolve, reject);
                }catch(err){
                    reject(err)
                }
            })
        })
    }
    else if(this.state == FULFILLED){
        return bridgePromise = new MyPromise((resolve, reject) => {
            setTimeout(() => {
                try{
                    const x = onFulfilled(self.value)
                    resolvePromise(bridgePromise, x, resolve, reject);
                }catch(err){
                    reject(err)
                }
            })
        })
    }
    else{
        return bridgePromise = new MyPromise((resolve, reject) => {
            setTimeout(() => {
                try{
                    const x = onRejected(self.error)
                    resolvePromise(bridgePromise, x, resolve, reject);
                }catch(err){
                    reject(err)
                }
            })
        })
    }
}

MyPromise.prototype.catch = function(onRejected) {
    return this.then(null, onRejected)
}
const promise = (name) => {
    return new MyPromise((resolve, reject) => {
        resolve(name)
    })
}
promise('1111').then(res => {
    console.log(res)
    return promise('22222')
}).then(res => {
    console.log(res)
})
new MyPromise((resolve, reject) => {
    resolve('222')
}).then(res => {
    console.log(res)
})
// 1111
// 222
// 22222

# 参考