一、基础版 Promise
观察 Promise 表象
- Promise 需要使用 new 关键字实例化。
- Promise 首个参数是回调函数,且该回调函数是立即执行的。
- 执行器(回调函数)有两个参数,分别是 resolve 和 reject,在执行器内部可以通过括号调用。
- Promise 有三种状态,状态间存在规则且不可逆。
- resolve 和 reject 调用时改变 Promise 的状态。
- Promise then 方法 存在两个函数类型的参数,一个是成功时调用,一个是失败时调用。
- then 方法第一个回调函数参数是成功返回的结果值,该结果值为 resolve 调用时传入的值。第二个回调函数参数是失败返回的错误对象。
通过观察 Promise 表象得出的:需实现功能(和表象一一对应)
- Promise 是一个类。
- 通过new 实例化一个 Promise 类时,需要传递一个执行器(回调函数)进去,执行器会立即执行。
- 执行器有两个参数,参数类型皆是函数。
- Promise 有三个状态:pending、fulfilled、rejected,pending->fulfilled/pending->rejected,一旦状态确定就不可更改。
- 执行器参数函数调用时改变状态,resolve 和 reject 用来更改状态。
- 实现 then 方法,接受两个参数,参数类型为函数,Promise 状态更改为 fulfilled 时调用第一个参数,状态更改为 rejected 时调用第二个参数。
- resolve 接受一个值,在then 方法第一个回调函数执行时作为默认参数传入。reject 方法接收一个异常对象,在 then 方法第二个回调函数执行时作为默认参数传入。
Promise 基础实现
上述条件完成后我们基本可以实现一个基础 Promise 类。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class PromiseM {
status = PENDING; // promise 状态
value = undefined; // 成功之后的值
error = undefined; // 失败后的原因
constructor(fn) {
return fn(this.resolve, this.reject);
}
resolve = (value) => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功后的值
this.value = value;
};
reject = (error) => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.error = error;
};
then = (successCallBack, failCallBack?) => {
if (this.status === FULFILLED) {
return successCallBack(this.value);
}
if (this.status === REJECTED) {
return failCallBack(this.error);
}
throw false;
}
}
我们可以如下调用实验是否完善:
const promiseM = new PromiseM((resolve, reject) => {
resolve(1);
// reject('fail')
}).then((res) => {
console.log(res);
}, error => {
console.log(error)
})
二、标准版 Promise
下面我们先阐述一些需要特殊补充的功能点,最后我们再把每一个功能点一一放出,最终再放上最终版代码。
1. Promise 异步处理
const promiseM = new PromiseM((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 2000)
}).then((res) => {
console.log(res);
}, error => {
console.log(error);
})
2. 一个 Promise 实例多次调用 then 方法(同步、异步都要考虑)
const promiseM = new PromiseM((resolve, reject) = {
setTimeout(() => {
resolve('success')
}, 2000)
})
promiseM.then(res => {
console.log(res);
}, error => {
console.log(error)
})
promiseM.then(res => {
console.log(res);
}, error => {
console.log(error)
})
3. Promise then 链式调用、then 方法返回值
- then 方法可以被链式调用。
- then 方法会返回一个全新的 Promise 对象。
- 后面 then 方法回调函数拿到的值是上一个 then 方法的返回值。
- then 方法可以返回一个值或一个 Promise 对象。
promiseM.then(res => {
return 1
}).then(res => {
console.log(res)
})
4. 校验之避免循环调用
const m = promiseM.then(res => {
return m
})
5. 错误处理
- 执行器函数中出现错误时,触发 reject 并捕获异常
- then 回调函数调用时出现错误,触发下一个 then 的 reject
- then 回调函数的 REJECT status 的处理,以使 reject 状态下也可以达到链式调用,向下传递至下个 then
// 执行器 抛出异常
const promiseM = new PromiseM((resolve, reject) => {
throw new Error('executor error')
})
// then 抛出异常
const promiseM = new PromiseM((resolve, reject) => {
resolve(1)
})
promiseM.then(() => {
throw new Error('executor error')
}).then(() => {}, (error) => {
console.log(error.message)
})
// reject 链式调用
const promiseM = new PromiseM((resolve, reject) => {
reject('失败')
})
promiseM.then(value => {
console.log(value)
}, error => {
console.log(error)
return 10000
}).then(value => {
console.log(value)
})
6. 处理异步情况
console.log(1)
const promiseM = new PromiseM((resolve, reject) => {
setTimmeout(() => {
resolve('resolve')
}, 1000)
})
console.log(2)
promiseM.then(res => {
console.log(4)
return 1
}).then(res => {
console.log(res)
})
console.log(3)
Code 2-1:Promise 异步处理
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class PromiseM {
status = PENDING; // promise 状态
value = undefined; // 成功之后的值
error = undefined; // 失败后的原因
successCallBack = undefined;
failCallBack = undefined;
constructor(fn) {
return fn(this.resolve, this.reject);
}
rosolve = (value) => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功后的值
this.value = value;
// 判断成功回调是否存在,如果存在则调用
this.successCallBack && this.successCallBack(this.value)
};
reject = (error) => {
// 如果状态不是等待 组织程序向下执行
if (this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.error = error;
// 判断失败回调是否存在,如果存在则调用
this.failCallBack && this.failCallBack(this.value)
};
then = (successCallBack, failCallBack?) => {
if(this.status === FULFILLED) {
return successCallBack(this.value);
}
if(this.status === REJECTED) {
return failCallBack(this.error)
}
this.successCallBack = successCallBack
this.failCallBack = failCallBack
}
}
Code 2-2:一个 Promise 实例多次调用 then 方法
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class PromiseM {
status = PENDING; // promise 状态
value = undefined; // 成功之后的值
error = undefined; // 失败后的原因
successCallBack = [];
failCallBack = [];
constructor(fn) {
return fn(this.resolve, this.reject);
}
resolve = (value) => {
// 如果状态是不是等待 组织程序向下执行
if(this.status !== PENDING) return
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功后的值
this.value = value;
// 判断成功回调是否存在,如果存在则调用,通过循环依次调用
while(this.successCallBack.length > 0) {
this.successCallBack.shift()(this.value)
}
};
reject = (error) => {
// 如果状态不是等待 组织程序向下执行
if(this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.error = error;
// 判断失败回调是否存在,如果存在则调用,通过循环依次调用
while(this.failCallBack.length > 0) {
this.failCallBack.shift()(this.value)
}
};
then = (successCallBack, failCallBack?) => {
if(this.status === FULFILLED) {
return successCallBack(this.value)
}
if(this.status === REJECTED) {
return failCallBack(this.error)
}
this.successCallBack.push(successCallBack)
this.failCallBack.push(failCallBack)
}
}
Code 2-3: Promise then 链式调用、then 方法返回值
then = (successCallback, failCallBack?) => {
console.log('then', this.status);
return new PromiseM((resolve, reject) => {
if(this.status === FULFILLED) {
console.log(this.value, 'success');
return resolvePromise(successCallBack(this.value), resolve, reject);
}
if(this.status === REJECTED) {
return failCallBack(this.error)
}
this.successCallBack.push(successCallBack)
this.failCallBack(failCallBack)
})
}
function resolvePromise(x, resolve, reject) {
if(x instanceod PromiseM) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
Code 2-4:校验之避免循环调用
then = (successCallBack, failCallBack?) => {
const promise2 = new PromiseM((resolve, reject) => {
if(this.status === FULFILLED) {
return setTimeout(() => {
resolvePromise(promise2, successCallBack(this.value), resolve, reject);
}, 0)
}
if(this.status === REJECTED) {
return failCallBack(this.error)
}
this.successCallBack.push(successCallBack)
this.failCallBack.push(failCallBack)
})
return promise2
};
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<promise>'))
}
if(x instanceof PromiseM) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
Code 2-5:错误处理
constructor(fn) {
try {
fn(this.resolve, this.reject);
} catch (error) {
this.reject(error)
}
}
then = (successCallBack, failCallBack?) => {
const promise2 = new PromiseM((resolve, reject) => {
if(this.status === FULFILLED) {
return setTimeout(() => {
try {
resolvePromise(promise2, successCallBack(this.value), resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
}
if(this.status === REJECTED) {
return failCallBack(this.error)
}
this.successCallBack.push(successCallBack)
this.failCallBack.push(failCallBack)
})
return promise2
}
Code 2-6:处理异步情况 (需要重点理解)
resolve = (value) => {
// 如果状态不是等待 组织程序向下执行
if(this.status !== PENDING) return
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功后的值
this.value = value;
console.log('IN RESOLVE');
// 判断成功回调是否存在,如果存在则调用
while (this.successCallback.length > 0) {
this.successCallBack.shift()()
}
};
reject = (error) => {
// 如果状态不是等待 组织向下执行
if(this.status !== PENDING) return
// 将状态更改为失败
this.status = REJECTED;
// 判断失败回调是否存在,如果存在则调用
while (this.failCallBack.length > 0) {
this.failCallBack.shift()()
}
};
then = (successCallBack, failCallBack?) => {
const promise2 = new PromiseM((resolve, reject) => {
if(this.status === FULFILLED) {
return setTimeout(() => {
try {
resolvePromise(promise2, successCallBack(this.value), resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
}
if(this.status === REJECTED) {
return setTimeout(() => {
try {
resolvePromise(promise2, failCallBack(this.error), resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
}
this.successCallBack.push(() => {
setTimeout(() => {
try {
resolvePromise(promise2, successCallBack(this.value), resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallBack.push(() => {
setTimeout(() => {
try {
resolvePromise(promise2, failCallBack(this.error), resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
})
})
return promise2
}
三、核心版 Promise
我们还需要处理一些细节,以及 Promise.all 等功能方法。
1. then 方法参数问题
- then 方法的 resolve/reject 两个参数都是可选参数
- 没有回调函数的 then 方法 会将 Promise 的状态依次向后传递,直到传递至存在回调函数的 then 方法
- then 若没有传递参数,则自动补充一个回调函数:获取 resolve 返回值并直接 return,以达到状态传递的效果
// 示例 1
const promiseM = new PromiseM((resolve, reject) => {
resolve('resolve')
})
promiseM.then().then().then(res => {
console.log(res)
})
// resolve
// 示例 2
const promiseM = new PromiseM((resolve, reject) => {
reject('reject')
})
promiseM.then().then().then(res => {
console.log(res)
}, error => {
console.log(error)
})
我们需要实现如下面的功能:
promiseM.then().then().then(res => {
console.log(res)
})
// ↓↓↓↓↓↓↓↓↓ 自动补充如下
promiseM.then(value => value).then(value => value).then(res => {
console.log(res)
})
2. Promise.all 方法的实现
- 按照异步代码调用的顺序得到异步代码执行的结果,调用的顺序一定是结果的顺序
- 数组参数里接收任何类型:Promise 或对象等
- 返回值是一个 Promise 对象,且可以链式调用 then 方法
- all 方法中所有的 Promise 对象的状态都是成功时 all 方法最后的状态也是成功的,若存在一个失败,则其状态也会是失败的
- all 方法是一个静态方法,为解决异步并发问题
const func_1 = () => {
return new PromiseM((resolve, reject) => {
setTimeout(() => {
resolve('func_1')
}, 2000)
})
}
const func_2 = () => {
return new PromiseM((resolve, reject) => {
resolve('func_2')
})
}
PromiseM.call(['a','b'func_1(),func_2(),'c']).then(function(result){
// result -> ['a','b','func_1','func_2','c']
})
3. Promise.resolve 方法的实现
- 将给定的值转换为 Promise 对象,如果给定值为 Promise 类型,则原封不动传递回去
- 返回值为一个 Promise 对象,该对象会包裹通过参数传递进去的值
- resolve 方法是一个静态方法
const func_1 = () => {
return new PromiseM((resolve, reject) => {
resolve('func_1')
})
}
PromiseM.resolve(10).then(value => console.log(value))
PromiseM.resolve(func_1()).then(value => console.log(value))
// 10
// func_1
4. finally 方法的实现
- 无论当前 Promise 状态是成功还是失败,finally 里的回调函数总会被执行
- finally 也能够通过链式调用 then 的方式获取当前 Promise 最终返回的结果
- 不是静态方法
- finally 的回调函数里也可以 return 一个值,以达到链式调用目的,且调用顺序需注意
const promise_1 = new PromiseM((resolve, reject) => {
setTimeout(() => {
resolve('promise_1')
}, 2000)
})
console.log('-------------');
const promise_2 = new PromiseM((resolve, reject) => {
reject('失败')
})
promise_2.finally(() => {
console.log('finally_2')
return promise_1
}).then(value => {
console.log(value)
}, error => {
console.log(error)
})
// finally_2
// 失败
5. catch 方式的实现
- 用于处理当前 Promise 对象最终状态为失败时的情况
- 如果不传递失败回调,那么当 Promise 失败时,触发 catch 方法中的回调函数
- 可在 catch 后链式调用其他方法
const promise = new PromiseM((resolve, reject) => {
reject('失败')
})
promise.then(value => console.log(value))
.catch(error => console.log(error))
Code 3-1:then 方法参数问题
then = (successCallBack?, failCallBack?) => {
successCallBack = successCallBack ? successCallBack : value => value
failCallBack = failCallBack ? failCallBack : error => { throw error }
......
}
Code 3-2:Promise.all 方法的实现
static all(array) {
let result = []
let i = 0
retrun new PromiseM((resolve, reject) => {
function addData(key, value) {
result[key] = value
i++
if(i === array.length) {
resolve(result)
}
}
array.forEach((current, index) => {
if(current instanceof PromiseM) {
current.then(value => addData(index, value), error => reject(error))
} else {
addData(index, current)
}
})
})
}
Code 3-3:Promise.resolve 方法的实现
static resolve(value) {
if(value instanceof PromiseM) return value;
return new PromiseM((resolve) => resolve(value));
}
Code 3-4:finally 方法的实现
finally = (callback) => {
return this.then(value => {
return PromiseM.resolve(callback()).then(() => value)
}, error => {
return PromiseM.resolve(callback()).then(() => { throw error })
})
}
Code 3-5:catch 方法的实现
catch(failCallBack) {
return this.then(undefined, failCallBack)
}
四、完整版 Promise
整合代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class PromiseM {
status = PENDING; // promise 状态
value = undefined; // 成功之后的值
error = undefined; // 失败后的原因
successCallBack = [];
failCallBack = [];
constructor(fn) {
try {
fn(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
resolve = (value) => {
// 如果状态不是等待 组织程序向下执行
if(this.status !== PENDING) return;
// 将状态更改为成功
this.status = FULFILLED;
// 保存成功后的值
this.value = value
// 判断成功回调是否存在,如果存在则调用
while(this.successCallBack.length > 0) {
this.successCallBack.shift()();
}
}
reject = (error) => {
// 如果状态不是等待 组织程序向下执行
if(this.status !== PENDING) return;
// 将状态更改为失败
this.status = REJECTED;
// 保存失败后的原因
this.error = error
// 判断失败回调是否存在,如果存在则调用
while(this.failCallBack.length > 0) {
this.failCallBack.shift()();
}
}
then = (successCallBack?, failCallBack?) => {
successCallBack = successCallBack ? successCallBack : (value) => value;
failCallBack = failCallBack
? failCallBack
: (error) => {
throw error;
}
const promise2 = new PromiseM((resolve, reject) => {
if(this.status === FULFILLED) {
retrun setTimeout(() => {
try {
resolvePromise(
promise2,
successCallBack(this.value),
resolve,
reject
);
} catch (error) {
reject(error)
}
}, 0)
}
if(this.status === REJECTED) {
return setTimeout(() => {
try {
resolvePromise(promise2, failCallBack(this.error), resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
this.successCallBack.push(() => {
setTimeout(() => {
try {
resolvePromise(
promise2,
successCallBack(this.value),
resolve,
reject
)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallBack.push(() => {
setTimeout(() => {
try {
resolvePromise(promise2, failCallBack(this.error), resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
})
return promise2
}
finally = (callback) => {
return this.then(value => {
return PromiseM.resolve(callback()).then(() => value)
}, error => {
return PromiseM.resolve(callback()).then(() => { throw error })
})
}
catch(failCallBack) {
return this.then(undefined, failCallBack)
}
static all(array) {
let result = [];
let i = 0;
return new PromiseM((resolve, reject) => {
function addData(key, value) {
result[key] = value;
i++;
if(i === array.length) {
resolve(result)
}
}
array.forEach((current, index) => {
if(current instanceof PromiseM) {
current.then(
(value) => addData(index, value),
(error) => reject(error)
)
} else {
addData(index, current)
}
})
})
}
static resolve(value) {
if(value instanceof PromiseM) return value;
return new PromiseM((resolve) => resolve(value));
}
}
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<Promise>')
)
}
if(x instanceof PromiseM) {
x.then(resolve, reject)
} else {
resolve(x)
}
}