一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情
🎉前言
Promise 不管是日常开发还是面试中,都是大家经常碰到的,所以掌握它是很有必要的,了解它的原理就能在遇到问题时能够更快的定位哦。
相信大家有了第一章节的基础,对 Promise 也有了一定的了解,这一期文章就带大家将剩下的功能实现吧。
🎊 实现前准备
我们把在第一章节 延迟调用 的代码实现稍微改一下:
// 初始化值
initValue () {
//...省略代码
// 把回调结果保存起来
+ this.onFulfilledList = [];
+ this.onRejectedList = [];
}
resolve (value) {
//...省略代码
+ // 执行保存的函数
+ this.onFulfilledList.shift()(this.PromiseResult);
}
reject (reson) {
//...省略代码
+ // 执行保存的函数
+ this.onRejectedList.shift()(this.PromiseResult);
}
then (onFulfilled, onRejected) {
//...省略代码
// 如果状态为 fulfilled 就执行 onFulfilled
if (this.PromiseState === 'fulfilled') {
onFulfilled(this.PromiseResult);
// 否则如果状态为 rejected 就执行 onRejected
} else if (this.onRejected === 'rejected') {
onRejected(this.PromiseResult);
+ } else {
+ // 否则 就是 pending 状态,保存两个回调函数
+ this.onFulfilledList.push(onFulfilled);
+ this.onRejectedList.push(onFulfilled);
+ }
}
测试一下:
let test5 = new MyPromise((resolve,reject) => {
setTimeout(() => {
resolve('成功啦,兄嘚!!')
}, 1000);
}).then(res => {
console.log('res:', res); // 成功啦,兄嘚!!
}, err => {
console.log(err);
})
🍻 链式调用
Promise.then 方法支持 链式调用,下一次 then 的执行结果受上一次 then的返回值的影响,例子如下:
const test1 = new Promise((resolve, reject) => {
resolve(100) // 打印 200
}).then(res => {
return new Promise((resolve,reject) => {
resolve(2 * res)
})
},err => {
console.log(err);
}).then(res => {
console.log(res);
}, err => {
console.log(err);
})
上述结果可以总结出四个知识:
then方法本身会返回一个新的Promise对象。- 如果返回值是
Promise对象,返回值为成功,新Promise就是成功。 - 如果返回值是
Promise对象,返回值为失败,新Promise就是失败。 - 如果返回值非
Promise对象,新Promise对象就是成功,值为此返回值。
值得一提的是,第2点和第3点可以简单一句话概况:Promise 的最终状态以最后一次为准。
那如何实现 then 完还能再 then 呢?答案是,then 完一次后在返回一次 Promise 对象就行了,有点像套娃的感觉。
具体实现(修改 then 里的逻辑):
then (onFulfilled, onRejected) {
// 校验两个参数是否是函数,这里使用 typeof
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : reson => { throw reson };
+ var thenPromise = new MyPromise((resolve,reject) => {
+ const resultPromise = cb => {
+ try {
+ //执行第一个(当前的)Promise的成功回调,并获取返回值
+ const x = cb(this.PromiseResult);
+ //如果是Promise,那么等待Promise状态变更,否则直接resolve
+ //这里resolve之后,就能被下一个.then()的回调获取到返回值,从而实现链式调用
+ x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
+ } catch (e) {
+ // 处理报错
+ reject(err);
+ throw new Error(err);
+ }
+ }
// 如果状态为 fulfilled 就执行 onFulfilled
if (this.PromiseState === 'fulfilled') {
+ resultPromise(onFulfilled);
// 否则如果状态为 rejected 就执行 onRejected
} else if (this.onRejected === 'rejected') {
+ resultPromise(onRejected);
} else {
// 否则 就是 pending 状态,保存两个回调函数
+ this.onFulfilledList.push(resultPromise.bind(this, onFulfilled));
+ this.onRejectedList.push(resultPromise.bind(this, onRejected));
}
})
// 返回这个包装的Promise
return thenPromise;
}
测试代码:
const test2 = new MyPromise((resolve, reject) => {
resolve(100) // 打印: 成功==> 200
}).then(res => {
return new MyPromise((resolve,reject) => {
resolve(2 * res)
})
},err => {
return new MyPromise((resolve,reject) => {
resolve(3 * err)
})
}).then(res => {
console.log('成功==>', res)
}, err => {
console.log('失败==>', err)
})
♠️ Promise.all
Promise.all的返回值是一个新的Promise实例。
Promise.all接受一个可遍历的数据容器,容器中每个元素都应该是Promise的实例。假设这个容器是一个数组。只有当数组中的每个
Promise实例都成功时Promise.all才会返回成功。这些Promise实例所有的resolve结果会按照原来的顺序集合在一个数组中作为Promise.all的resolve的结果。数组中只要有一个
Promise实例失败,那么Promise.all就会失败。Promise.all的.catch()会捕获到这个reject。
原生 Promise.all 的效果:
const test1 = Promise.resolve('test1')
const test2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('test2 延时一秒')
}, 1000)
})
const test3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('test3 延时两秒')
}, 2000)
})
const test4 = Promise.reject('test4 rejected')
const test5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('test5 rejected 延时1.5秒')
}, 1500)
})
// 所有Promise实例都成功
Promise.all([test1, test2, test3])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // 2秒后打印 [ 'test1', 'test2 延时一秒', 'test3 延时两秒' ]
// 一个Promise实例失败
Promise.all([test1, test2, test4])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // test4 rejected
// 一个延时失败的Promise
Promise.all([test1, test2, test5])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // 1.5秒后打印 test5 rejected
// 两个Promise实例失败
Promise.all([test1, test4, test5])
.then(res => {
console.log(res)
})
.catch(err => console.log(err)) // test4 rejected
这里要注意的是:
- 如果有两个Promise实例失败了,则返回最后一个。
- 如果有异步的情况,例如
setTimeout,则返回结果不定。
🎼 手动实现
Promise.MyAll 接收一个数组,返回一个新的 Promise 实例。
Promise.MyAll = function (promises) {
let arr = [], count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
arr[index] = res;
// 成功后 +1
count += 1;
// 判断是否相等
if (count === promises.length) resolve(arr);
}, reject)
})
})
}
我们需要一个数组来收集这些 Promise 实例的 resolve 结果。需要一个计算器,记录Promise 实例的成功,成功后,计算器 +1。计算结束后,如果计算总数等于 promises 的个数,就执行 resolve,否则就是失败,执行 reject。
♥️ Promise.any
Promise.any 与 Promise.all 可以看做是相反的。Promise.any 中只要有一个 Promise 实例成功就成功,只有当所有的 Promise 实例失败时 Promise.any 才失败。
🎼 手动实现
Promise.MyAny = function (promises) {
let arr = [],count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item, index) => {
Promise.resolve(item).then(resolve, err => {
arr[i] = { status: 'rejected', val: err };
count += 1;
if (count === promises.length) reject(new Error('no promise succeeded'));
})
})
})
}
这里跟 Promise.all 类似,也需要一个数组和计数器,用计数器判断是否所有的 Promise 实例都失败。
♣️ Promise.race
Promise 的赛跑模式,以状态变化最快的那个 Promise 实例为准,最快的 Promise 成功 Promise.race 就成功,最快的 Promise 失败 Promise.race 就失败。
🎼 手动实现
Promise.MyRace = function (promises) {
return new Promise((resolve, reject) => {
for (const item of promises) {
Promise.resolve(item).then(resolve, reject)
}
})
}
♦️ Promise.allSettled
Promise.allSettled()方法返回一个在所有给定的 Promise 都已经 fulfilled 或 rejected 后的Promise,并带有一个对象数组,每个对象表示对应的Promise结果。
🎼 手动实现
我们用个数组把所有的 Promise 实例的结果(无论成功与否)都收集起来,判断收集完了(所有 Promise 实例状态都改变了),咱就将这个收集到的结果 resolve 掉。收集成功 Promise 结果的逻辑咱们在 Promise.all 中实现过,收集失败 Promise 结果咱们在 Promise.any 中处理过。
Promise.MyAllSettled = function (promises) {
let arr = [],count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item, index) => {
Promise.resolve(item).then(res => {
arr[i] = { status: 'fulfilled', val: res };
count += 1;
if (count === promises.length) resolve(arr);
}, (err) => {
arr[i] = { status: 'rejected', val: err };
count += 1
if (count === promises.length) resolve(arr);
})
})
})
}
上述的代码跟 Promise.any 也有些类似,就是加了对 fulfilled 的收集而已。
✨总结
以上就是本次分享的全部内容~~
如果觉得文章写得不错,对你有所启发的,请不要吝啬 点个 赞 和 关注 并在 评论区 留下你宝贵的意见哦~~😃