# 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() 之后一起执行,那怎么办呢?
需要将 onFulfilled
和 onRejected
改为数组,调用 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;
}
接下来将 resolve
和 reject
方法中执行回调的部分进行修改
遍历调用所有方法:
// 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