![3c5feb67e99b38d4ea77e6434abb0c84.png](https://i-blog.csdnimg.cn/blog_migrate/d87d9dd760ded9b8f701bc502a30ca87.jpeg)
手写简单promise
1.分析promise核心逻辑
先看一段代码
let p = new Promise();
//说明Promise是一个类(class),需要new实例化
let p = new Promise((resolve, reject) => {
resolve('success');
});
console.log(p) //Promise { 'success' }
//Promise类的构造函数接受一个参数,该参数是一个函数(执行器函数,可以参照mdn中promise说明),执行器函数在实例化后立即执行(resolve或reject)
let p = new Promise((resolve, reject) => { });
console.log(p) //Promise { <pending> }
let p1 = new Promise((resolve, reject) => {
resolve('success');
});
console.log(p1) //Promise { 'success' }
let p2 = new Promise((resolve, reject) => {
reject('fail');
});
console.log(p2) //Promise { <rejected> 'fail' }
let p3 = new Promise((resolve, reject) => {
resolve('success');
reject('fail');
});
console.log(p3) //Promise { 'success' }
//Promise有三种状态,分别是pending/fulfilled/rejected
//一旦状态确定就不可更改
//resolve和reject函数是用来更改状态的 resolve: fulfilled reject: rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected;(参考聘,可以自己动手试试先执行reject、后执行resolve,打印看看结果)
let p = new Promise((resolve, reject) => {
resolve('success');
//reject('fail');
});
p.then(
//成功回调 onfulfilled
value => {
console.log(value) //sucess
},
//失败回调 onrejected
reason => {
console.log(reason) //fail
}
)
//then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
//then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
从以上代码可以总结以下几点
- Promise是一个类(class),需要new实例化
- Promise类的构造函数接受一个参数,该参数是一个函数(执行器函数,可以参照mdn中promise说明),执行器函数在实例化后立即执行(resolve或reject)
- Promise有三种状态,分别是pending/fulfilled/rejected,一旦状态确定就不可更改
- 状态改变只能是pending=>fulfilled 或者 pending=>rejected;
- resolve和reject函数是用来更改状态的 resolve: fulfilled reject: rejected
- then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
- then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
手动实现符合上面几点的类(myPromise)
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
successCallback = ''
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
failCallback = ''
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
//setTimeout异步执行,将promise2传入resolvePromise
if (this.status == FULFILLED) {
successCallback(this.value)
} else if (this.status == REJECTED) {
failCallback(this.reason)
}
}
}
2.解决异步逻辑的问题
上面的代码基本实现了之前总结的promise的特点,但是当我们异步调用执行器函数的resolve或reject方法时,会出现问题,不能打印成功回调的参数
如下报错示例2-1
const MyPromise = require('./2-Promise');
let p = new MyPromise((resolve, reject) => {
//异步执行resolve
setTimeout(() => {
resolve('success');
}, 1000);
//reject('fail');
});
p.then(
//成功回调 onfulfilled
value => {
console.log(value) //不能成功输出success
},
//失败回调 onrejected
reason => {
console.log(reason)
}
)
//异步执行resolve时,成功回调 onfulfilled不能接收到参数
为什么会出现以上问题了?是由于当执行器函数异步执行时,then方法不能及时收到promise的状态
![ac472870c05e009ba5cd640407f99a51.png](https://i-blog.csdnimg.cn/blog_migrate/06084c3452e277f4505a39aa2eeb00c0.png)
所以修改myPromise如下
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
successCallback = ''
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
failCallback = ''
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
//成功回调函数是否存在,存在则执行
this.successCallback && this.successCallback(this.value)
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
//失败回调函数是否存在,存在则执行
this.failCallback && this.failCallback(this.reason)
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
//setTimeout异步执行,将promise2传入resolvePromise
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;
此时示例2-1的代码再测试可以成功打印success,说明异步问题解决
3.实现then方法的多次调用添加多个处理函数
上面的类基本实现then的单次调用,但当我们多次调用,仍然会出现问题
报错示例3-1
const MyPromise = require('./1-Promise');
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 10);
//reject('fail');
});
p.then(
//成功回调 onfulfilled
value => {
console.log(1, value) //不能成功输出1 success
}
)
p.then(
//成功回调 onfulfilled
value => {
console.log(2, value) //能成功输出2 success
}
)
//问题:第一个then不能成功输出
异步多次调用then的时候会出现这种情况。出现这种情况的原因是当status处于pending状态时,我们会储存成功回调和失败回调,但是由于我们是以单变量方式储存,会导致后一个异步then调用的成功/失败回调会覆盖上一个then的成功/失败回调。
解决方案:将类的属性成功/失败回调以数组的方式调用 successCallback = [] failCallback = []
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
successCallback = []
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
failCallback = []
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
//遍历成功回调函数数组并执行
while (this.successCallback.length) {
this.successCallback.shift()(this.value)
}
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
//遍历失败回调函数数组并执行
while (this.failCallback.length) {
this.failCallback.shift()(this.reason)
}
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
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;
示例代码3-1测试通过
4.实现then方法的链式调用
正常的Promise类可以实现链式调用,then方法的返回值应该是一个新的Promise,上面封装的类并没有实现这个特征
所以对then方法做出如下改写(仅仅改写成功回调)
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
//返回promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
let x = successCallback(this.value)
resolve(x)
} else if (this.status == REJECTED) {
failCallback(this.reason)
} else {
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
});
return promise2
}
上面的改写会有一个问题,没有考虑successCallback(this.value)执行的异常及返回值。
当successCallback(this.value)执行异常时,需要走到reject,所以此处应当添加try{}catch(){}
当successCallback(this.value)返回值为promise时,不能直接调resolve(x)
所以做出如下分析,并封装函数处理
//判断回调结果是普通值还是promise对象
//如果是普通值直接执行resolve(x),传递x到then的成功回调
//如果是promise,判断promise返回的结果
//根据结果决定调用resolve还是调用reject
//封装函数、方便调用
then方法改写和封装处理函数dealPromise如下
then = (successCallback, failCallback) => {
//返回promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
try {
let x = successCallback(this.value)
dealPromise(x,resolve,reject)
} catch (e) {
reject(e)
}
} else if (this.status == REJECTED) {
failCallback(this.reason)
} else {
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
});
return promise2
}
//类的外部封装
function dealPromise(x, resolve, reject) {
//判断x是否是promise对象,如果是,根据x的执行结果回调传值
//如果x是普通值,直接调用resolve(x)
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
上面的改写基本实现了then的链式调用,完全改写类如下
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
successCallback = []
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
failCallback = []
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
//遍历成功回调函数数组并执行
while (this.successCallback.length) {
this.successCallback.shift()()
}
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
//遍历失败回调函数数组并执行
while (this.failCallback.length) {
this.failCallback.shift()()
}
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
//返回promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
try {
let x = successCallback(this.value)
dealPromise(x, resolve, reject)
} catch (e) {
reject(e)
}
} else if (this.status == REJECTED) {
try {
let x = failCallback(this.reason)
dealPromise(x, resolve, reject)
} catch (e) {
reject(e)
}
} else {
this.successCallback.push(() => {
try {
let x = successCallback(this.value)
dealPromise(x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.failCallback.push(() => {
try {
let x = failCallback(this.reason)
dealPromise(x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
});
return promise2
}
}
function dealPromise (x, resolve, reject) {
//判断x是否是promise对象,如果是,根据x的执行结果回调传值
//如果x是普通值,直接调用resolve(x)
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise;
5.解决then的链式调用识别自身的问题,避免死循环;解决then方法的参数变成可选参数
看如下示例
let p = new Promise((resolve, reject) => {
resolve('success');
});
let p1 = p.then(
//成功回调 onfulfilled返回promise自身
value => {
return p1;
}
)
//捕捉异常
p1.catch(
reason => {
console.log(reason) //抛出错误[TypeError: Chaining cycle detected for promise #<Promise>]
}
)
Promise返回自身会抛出异常,我上面封装的Promise并没有考虑这种情况,所以再dealPromise函数中需要判断promise是否返回的是自身,如果返回自身,则抛出异常,实现后如下(其中类中做了setTimeout处理是为了方便拿到promise2)
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
successCallback = []
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
failCallback = []
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
//遍历成功回调函数数组并执行
while (this.successCallback.length) {
this.successCallback.shift()(this.value)
}
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
//遍历失败回调函数数组并执行
while (this.failCallback.length) {
this.failCallback.shift()(this.reason)
}
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
successCallback = successCallback ? successCallback : (value) => value
failCallback = failCallback? failCallback : (reason) => { throw reason }
//返回promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status == FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value)
dealPromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status == REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason)
dealPromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
dealPromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason)
dealPromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
});
return promise2
}
}
function dealPromise (promise2, x, resolve, reject) {
//判断回调返回值x是否等于promise2,如果相等,为了避免死循环,直接返回失败回调
if (x === promise2) {
return reject(
new Error('Chaining cycle detected for promise #<Promise>')
)
}
//判断x是否是promise对象,如果是,根据x的执行结果回调传值
//如果x是普通值,直接调用resolve(x)
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise;
6.catch方法的实现
catch的实质是then(undefind,onrejected),实现如下
catch = (failCallback) => {
return this.then(undefined, failCallback)
}
//在类中添加catch方法
7.静态方法resolve和reject的实现
resolve方法根据参数类型不同,返回结果不同
当参数是普通值,返回一个新的promise,并将参数直接resolve
当参数是promise对象,直接返回对象
//静态方法 resolve
static resolve(data) {
if (data instanceof MyPromise) {
return data
} else {
return new MyPromise((resolve, reject) => {
resolve(data)
})
}
}
reject的实现类似
//静态方法 reject
static reject(data) {
if (data instanceof MyPromise) {
return data
} else {
return new MyPromise((resolve, reject) => {
reject(data.message || data)
})
}
}
8.静态方法all的实现
//静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败
//原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响
//静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败
//原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响
static all = (array) => {
//结果数组
let result = []
//结果数组的长度,初始长度为0
let index = 0
return new MyPromise((resolve, reject) => {
let addData = (key, value) => {
//保证结果数组的顺序与初始参数数组顺序一致
result[key] = value
index++
//参数数组与结果数组长度一致才成功回调,保证成功回调不受参数数组中promise的异步影响
//保证参数数组中的promise对象全部成功,all方法才执行成功回调、否则失败
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let cur = array[i]
//当前值为promise对象
if (cur instanceof MyPromise) {
cur.then(
(value) => addData(i, value),
(reason) => {
reject(reason)
}
)
} else {
//普通值
addData(i, array[i])
}
}
})
}
9.静态方法race的实现
race方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
参数一般是数组,数组中的哪个promise执行最快,就直接返回该promise的结果,由于最快的promise已经定义了status的值FULFILLED或REJECTED
剩余的promise并不能更改原promise的状态,实现如下(跑的最快的那个自动更改status)
//静态方法 race
static race = (array) => {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let cur = array[i]
//当前值为promise对象
if (cur instanceof MyPromise) {
cur.then(
(value) => resolve(value),
(reason) => reject(reason)
)
} else {
//普通值
resolve(cur)
}
}
})
}
10.finally方法的实现
finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。
finally = (callback) => {
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value)
},
(reason) => {
return MyPromise.resolve(callback()).then(() => {
throw reason
})
}
)
}
11.最终手写的简单promise如下
//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
//执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
//调用resolve或调用reject会更改promise状态
//promise有三种状态,分别为pending/fulfilled/rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected
status = PENDING
//异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
value = undefined
//异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
reason = undefined
//then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
//定义成数组,方便多个回调储存
successCallback = []
//then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
//定义成数组,方便多个回调储存
failCallback = []
constructor(exe) {
//执行器函数立即执行
try {
exe(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = (value) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为FULFILLED
this.status = FULFILLED
//将resolve的参数放入类属性value,方便其他方法调用
this.value = value
//遍历成功回调函数数组并执行
while (this.successCallback.length) {
this.successCallback.shift()()
}
}
reject = (reason) => {
//判断status是否是pending状态,只有pending状态才可以继续往下执行
if (this.status !== PENDING) return
//异步成功执行,将status更改为REJECTED
this.status = REJECTED
//将reject的参数放入类属性reason,方便其他方法调用
this.reason = reason
//遍历失败回调函数数组并执行
while (this.failCallback.length) {
this.failCallback.shift()()
}
}
//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
then = (successCallback, failCallback) => {
successCallback = successCallback ? successCallback : (value) => value
failCallback = failCallback? failCallback : (reason) => { throw reason }
let promise2 = new MyPromise((resolve, reject) => {
//setTimeout异步执行,将promise2传入dealPromise
if (this.status == FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value)
//resolve(x)
//判断回调结果是普通值还是promise对象
//如果是普通值直接执行resolve(x),传递x到then的成功回调
//如果是promise,判断promise返回的结果
//根据结果决定调用resolve还是调用reject
//封装函数、方便调用
dealPromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else if (this.status == REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this.reason)
//reject(x)
//判断回调结果是普通值还是promise对象
//如果是普通值直接执行resolve(x),传递x到then的成功回调
//如果是promise,判断promise返回的结果
//根据结果决定调用resolve还是调用reject
//封装函数、方便调用
dealPromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
//resolve(x)
//判断回调结果是普通值还是promise对象
//如果是普通值直接执行resolve(x),传递x到then的成功回调
//如果是promise,判断promise返回的结果
//根据结果决定调用resolve还是调用reject
//封装函数、方便调用
dealPromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason)
//reject(x)
//判断回调结果是普通值还是promise对象
//如果是普通值直接执行resolve(x),传递x到then的成功回调
//如果是promise,判断promise返回的结果
//根据结果决定调用resolve还是调用reject
//封装函数、方便调用
dealPromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
//返回promise
return promise2
}
finally = (callback) => {
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value)
},
(reason) => {
return MyPromise.resolve(callback()).then(() => {
throw reason
})
}
)
}
catch = (failCallback) => {
return this.then(undefined, failCallback)
}
//静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败
//原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响
static all = (array) => {
//结果数组
let result = []
//结果数组的长度,初始长度为0
let index = 0
return new MyPromise((resolve, reject) => {
let addData = (key, value) => {
//保证结果数组的顺序与初始参数数组顺序一致
result[key] = value
index++
//参数数组与结果数组长度一致才成功回调,保证成功回调不受参数数组中promise的异步影响
//保证参数数组中的promise对象全部成功,all方法才执行成功回调、否则失败
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let cur = array[i]
//当前值为promise对象
if (cur instanceof MyPromise) {
cur.then(
(value) => addData(i, value),
(reason) => {
reject(reason)
}
)
} else {
//普通值
addData(i, array[i])
}
}
})
}
//静态方法 race
static race = (array) => {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let cur = array[i]
//当前值为promise对象
if (cur instanceof MyPromise) {
cur.then(
(value) => resolve(value),
(reason) => reject(reason)
)
} else {
//普通值
resolve(cur)
}
}
})
}
//静态方法 resolve
static resolve(data) {
if (data instanceof MyPromise) {
return data
} else {
return new MyPromise((resolve, reject) => {
resolve(data)
})
}
}
//静态方法 reject
static reject(data) {
if (data instanceof MyPromise) {
return data
} else {
return new MyPromise((resolve, reject) => {
reject(data.message || data)
})
}
}
}
function dealPromise(promise2, x, resolve, reject) {
//判断回调返回值x是否等于promise2,如果相等,为了避免死循环,直接返回失败回调
if (x === promise2) {
return reject(
new Error('Chaining cycle detected for promise #<Promise>')
)
}
//判断x是否是promise对象,如果是,根据x的执行结果回调传值
//如果x是普通值,直接调用resolve(x)
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise
不足之处或有错误的地方还请指正,谢谢
大前端高薪训练营(拉勾教育)part1-2学习笔记