如果想要手写promsie,需要先弄明白promise有哪些成员以及promise做了什么,开整!
1、promise是一个类,需要传入一个执行器,这个执行器有2个参数resolve和reject,并且执行器是立即调用的;有3种状态,存在status里面
-
pending:进行中 -
fulfilled:成功 -
rejected: 失败 上代码
class MyPromise {
constructor(excutor) {
excutor(this.resolve, this.reject)
}
status = PENDING;
value = undefined;
reason = undefined;
}
2、resolve用来将状态改为成功的状态fulfilled,并保存成功的值value,reject用来将状态改为失败的状态rejected,并保存失败的原因reason,需要注意的是状态只能由pending转为fulfilled或者由pending转为rejectd,这个过程是不可逆的,并且,状态一经改变,就不能再发生变化了。
class MyPromise {
.... //省略代码
value = undefined;
reason = undefined;
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value
}
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason
}
}
module.exports = MyPromise
3、promise还提供then方法执行回调函数,then方法接收2个参数,第1个参数为成功的回调函数successCallback,可以获取到resolve方法保存的value值;第2个参数为失败的回调函数failCallback,可以获取到reject方法保存的失败的原因reason。如果promise状态为fulfilled<则执行successCallback,如果promise状态为rejected,则执行failCallback方法。
class MyPromise {
... //省略代码
then(successCallback, failCallBack) {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
}
}
}
module.exports = MyPromise
4、promise执行器里面是支持异步的,但是调用promise的时候then方法会直接执行,由于异步执行,所以promise的状态还未改变,这时候需要将then方法传入的回调函数保存起来,等到promise的状态不为pending的时候再调用回调函数
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
...//省略代码
successCallback = undefined;
failCallBack = undefined;
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value
this.successCallback(this.value)
}
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason
this.failCallBack(this.reason)
}
then(successCallback, failCallBack) {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
} else {
this.successCallback = successCallback
this.failCallBack = failCallBack
}
}
}
module.exports = MyPromise
5、then方法是支持多次调用的,上面回调函数的保存,如果执行器是同步执行的情况下,是没有问题的,但是如果是异步的,那么我们就需要存储多个回调函数,所以需要把this.successCallback和this.failCallBack处理成数组,然后在状态改变之后,依次调用回调函数数组里面的成员
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
...//省略代码
successCallback = [];
failCallBack = [];
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value
while (this.successCallback.length) this.successCallback.shift()(this.value)
}
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason
while (this.failCallBack.length) this.failCallBack.shift()(this.reason)
}
then(successCallback, failCallBack) {
if (this.status === FULFILLED) {
successCallback(this.value)
} else if (this.status === REJECTED) {
failCallBack(this.reason)
} else {
this.successCallback.push(successCallback)
this.failCallBack.push(failCallBack)
}
}
}
module.exports = MyPromise
6、then方法支持链式调用,当前then拿到的值就是上一个then方法回调函数返回的值。因为then方法是promise提供的函数,所以要想实现链式调用,需要在then里面返回一个promise,并且通过这个返回的promise里面的resolve/reject来处理回调函数的返回值
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
...//省略代码
then(successCallback, failCallBack) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let x = successCallback(this.value)
resolve(x)
} else if (this.status === REJECTED) {
let x = failCallBack(this.reason)
reject(x)
} else {
this.successCallback.push(successCallback)
this.failCallBack.push(failCallBack)
}
})
return promise2
}
}
module.exports = MyPromise
7、then的回调函数里面返回的可能是一个普通值,也可能是一个promise对象,如果是一个普通值,直接按上面的处理是没问题的,但是如果返回一个promise对象,我们就需要判断这个promise对象的状态,如果成功,则调用resolve,如果失败则调用reject
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
... // 省略代码
then(successCallback, failCallBack) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let x = successCallback(this.value)
resolvePromise(x, resolve, reject)
} else if (this.status === REJECTED) {
let x = failCallBack(this.reason)
resolvePromise(x, resolve, reject)
} else {
this.successCallback.push(successCallback)
this.failCallBack.push(failCallBack)
}
})
return promise2
}
}
function resolvePromise (x, resolve, reject) {
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise
8、then方法链式调用识别promise对象自返回,链式调用返回的promise不能为当前promise本身
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
...//省略代码
then(successCallback, failCallBack) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 因为下面需要传入promise2,但是直接传的话,是获取不到promise2的,因为promise2还没定义完成,所以这里将这段代码处理成异步代码,就能获取到promise2
setTimeout(() => {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
}, 0)
} else if (this.status === REJECTED) {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} else {
this.successCallback.push(successCallback)
this.failCallBack.push(failCallBack)
}
})
return promise2
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('不能调用自身promise'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise
9、添加错误捕获增加代码的健壮性,异步调用方法补充
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(excutor) {
try {
excutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING;
value = undefined;
reason = undefined;
successCallback = [];
failCallBack = [];
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value
while (this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason
while (this.failCallBack.length) this.failCallBack.shift()(this.reason)
}
then(successCallback, failCallBack) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 因为下面需要传入promise2,但是直接传的话,是获取不到promise2的,因为promise2还没定义完成,所以这里将这段代码处理成异步代码,就能获取到promise2
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallBack.push(() => {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise2
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('不能调用自身promise'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise
10、then方法的参数是可选参数,如果不传参数就等同于
.then(value =>value, reason => reason)
修改代码,将then的参数变成可选参数
const { reject } = require("lodash")
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
... // 省略代码
then(successCallback, failCallBack) {
successCallback = successCallback ? successCallback : value => value;
failCallBack = failCallBack ? failCallBack : reason => reason;
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 因为下面需要传入promise2,但是直接传的话,是获取不到promise2的,因为promise2还没定义完成,所以这里将这段代码处理成异步代码,就能获取到promise2
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallBack.push(() => {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise2
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('不能调用自身promise'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise
11、实现Promise.all方法
all方法是一个静态方法all方法接收一个数组参数- 可以通过
.then方法接收返回结果,所以all方法返回一个promise all返回结果的顺序跟传入参数的顺序是一致的,不管是不是异步调用的
const { reject } = require("lodash")
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
static all(array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, val) {
index++
result[key] = val;
if (index === array.length) resolve(result)
}
for (let i = 0;i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => reject(reason))
} else {
addData(i, array[i])
}
}
})
}
module.exports = MyPromise
12、实现Promise.resolve方法,Promise.resolve方法可以将传入的参数转为promise
class MyPromise {
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value))
}
}
最后附上完整的代码
const { reject } = require("lodash")
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(excutor) {
try {
excutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING;
value = undefined;
reason = undefined;
successCallback = [];
failCallBack = [];
resolve = value => {
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value
while (this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason
while (this.failCallBack.length) this.failCallBack.shift()(this.reason)
}
then(successCallback, failCallBack) {
successCallback = successCallback ? successCallback : value => value;
failCallBack = failCallBack ? failCallBack : reason => reason;
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 因为下面需要传入promise2,但是直接传的话,是获取不到promise2的,因为promise2还没定义完成,所以这里将这段代码处理成异步代码,就能获取到promise2
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallBack.push(() => {
setTimeout(() => {
try {
let x = failCallBack(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise2
}
static all(array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, val) {
index++
result[key] = val;
if (index === array.length) resolve(result)
}
for (let i = 0;i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => reject(reason))
} else {
addData(i, array[i])
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value))
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('不能调用自身promise'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise