一:什么是 Promise
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
二:手写Promise
1、实例方法(catch、finally)
设计思路
内部调用then
处理异常
代码实现
<body><script>// 定义函数function runAsynctask(callback) {// callback 是一个回调函数// 调用核心apiif (typeof queueMicrotask === 'function') { // 调用三个函数是为了解决浏览器不兼容问题,先判断是不是函数queueMicrotask(callback)} else if (typeof MutationObserver === "function") {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, { childList: true })divNode.innerHTML = '打酱油改变以下内容'} else {setTimeout(callback, 0)}}const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class wePromise {state = PENDING // 状态result = undefined // 原因#handlers = [] // [{onFulfilled,onReject},......]// 构造函数constructor(func) {// 改状态,pending => fulfilledconst reslove = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = result// 下面这个是异步的时候,先保存,然后到这一步执行,就取出保存的函数并且执行this.#handlers.forEach(({ onFulfilled }) => { // 解构onFulfilled(this.result)})}}// 改状态,pending => rejectedconst reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({ onReject }) => {onReject(this.result)})}}// 异常的处理try {// 执行回调函数func(reslove, reject)} catch (error) {reject(error)}}then(onFulfilled, onReject) {// 判断传入的参数是不是函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonReject = typeof onReject === 'function' ? onReject : x => { throw x }const p2 = new wePromise((reslove, reject) => {// 判断执行完成后的状态if (this.state === FULFILLED) {runAsynctask(() => {try {// 获取返回值const x = onFulfilled(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {// 处理异常reject(error)}})} else if (this.state === REJECTED) {runAsynctask(() => {try {const x = onReject(this.result)reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})} else if (this.state === PENDING) { // 还没有改变状态,说明是异步// 保存回调函数this.#handlers.push({onFulfilled: () => {runAsynctask(() => {try {const x = onFulfilled(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})},onReject: () => {runAsynctask(() => {try {const x = onReject(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})}})}})return p2}catch(onReject) {// 内部调用then方法return this.then(undefined, onReject)}finally(onFinally){return this.then(onFinally,onFinally)}}function reslovePromise(p2, x, reslove, reject) {// 处理重复引用if (x === p2) {// 抛出错误throw new TypeError('Chaining cycle detected for promise #<Promise>')}// 处理返回的Promiseif (x instanceof wePromise) {// 调用then方法x.then(res => reslove(res), err => reject(err))} else {// 处理返回值reslove(x)}}// 创建对象,调用两个方法const p = new wePromise((reslove, reject) => {// reslove('success')// reject('reject')throw 'throw-error'})p.then(res => {console.log('成功回调1:', res);// throw 'throw-error'// return 2}).catch(err => {console.log('失败回调1:', err);}).finally(() => {console.log('finally');})</script>
</body>
运行效果
2、静态方法(reslove、reject、race)
reslove、reject设计思路
- 判断传入值
- Promise返回
- 转换为Promise返回
race设计思路
- 返回Promise
- 判断是否为数组
- 等待第一个敲定
all设计思路
- 返回Promise
- 判断是否为数组
- 空数组直接兑换
- 处理全部兑换(记录结果 --> 判断全部兑现)
- 处理第一个拒绝
allSettled设计思路
- 返回Promise
- 判断是否为数组
- 空数组直接兑换
- 等待全部敲定(记录结果 --> 处理兑换 或 拒绝)
any设计思路
- 返回Promise
- 判断是否为数组
- 空数组直接拒绝
- 等待结果(第一个兑现,全部拒绝)
代码实现
<body><script>// 定义函数function runAsynctask(callback) {// callback 是一个回调函数// 调用核心apiif (typeof queueMicrotask === 'function') { // 调用三个函数是为了解决浏览器不兼容问题,先判断是不是函数queueMicrotask(callback)} else if (typeof MutationObserver === "function") {const obs = new MutationObserver(callback)const divNode = document.createElement('div')obs.observe(divNode, { childList: true })divNode.innerHTML = '打酱油改变以下内容'} else {setTimeout(callback, 0)}}const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'class wePromise {state = PENDING // 状态result = undefined // 原因#handlers = [] // [{onFulfilled,onReject},......]// 构造函数constructor(func) {// 改状态,pending => fulfilledconst reslove = (result) => {if (this.state === PENDING) {this.state = FULFILLEDthis.result = result// 下面这个是异步的时候,先保存,然后到这一步执行,就取出保存的函数并且执行this.#handlers.forEach(({ onFulfilled }) => { // 解构onFulfilled(this.result)})}}// 改状态,pending => rejectedconst reject = (result) => {if (this.state === PENDING) {this.state = REJECTEDthis.result = resultthis.#handlers.forEach(({ onReject }) => {onReject(this.result)})}}// 异常的处理try {// 执行回调函数func(reslove, reject)} catch (error) {reject(error)}}then(onFulfilled, onReject) {// 判断传入的参数是不是函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => xonReject = typeof onReject === 'function' ? onReject : x => { throw x }const p2 = new wePromise((reslove, reject) => {// 判断执行完成后的状态if (this.state === FULFILLED) {runAsynctask(() => {try {// 获取返回值const x = onFulfilled(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {// 处理异常reject(error)}})} else if (this.state === REJECTED) {runAsynctask(() => {try {const x = onReject(this.result)reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})} else if (this.state === PENDING) { // 还没有改变状态,说明是异步// 保存回调函数this.#handlers.push({onFulfilled: () => {runAsynctask(() => {try {const x = onFulfilled(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})},onReject: () => {runAsynctask(() => {try {const x = onReject(this.result) // 返回结果reslovePromise(p2, x, reslove, reject)} catch (error) {reject(error)}})}})}})return p2}// 实例方法catch(onReject) {// 内部调用then方法return this.then(undefined, onReject)}finally(onFinally) {return this.then(onFinally, onFinally)}// 静态方法static reslove(value) {// 判断传入的是不是Promise对象if (value instanceof wePromise) {return value}return new wePromise((reslove, reject) => {reslove(value)})}static reject(value) {return new wePromise((reslove, reject) => {reject(value)})}static race(promises) {return new wePromise((reslove, reject) => {// 判断是否为数组if (!Array.isArray(promises)) {return reject(new TypeError('Argument is not iterable'))}// 等待第一个敲定promises.forEach(p => {wePromise.reslove(p).then(res => { reslove(res) }, err => { reject(err) })})})}// 重要static all(promises) {// 返回Promise实例return new wePromise((reslove, reject) => {// 判断是否为数组if (!Array.isArray(promises)) {return reject(new TypeError('Argument is not iterable'))}// 空数组直接兑换promises.length === 0 && reslove(promises)// 处理全部兑现const results = []let count = 0promises.forEach((p, index) => {wePromise.reslove(p).then(res => {results[index] = rescount++// 判断全部兑现count === promises.length && reslove(results)}, err => {// 处理第一个拒绝reject(err)})})})}static allSettled(promises) {// 返回Promise实例return new wePromise((reslove, reject) => {// 判断是否为数组if (!Array.isArray(promises)) {return reject(new TypeError('Argument is not iterable'))}// 空数组直接兑换promises.length === 0 && reslove(promises)// 等待全部敲定const results = []let count = 0promises.forEach(p => {// 之所以是使用这个静态方法,是因为这个将传入的对象包装成了wePromisewePromise.reslove(p).then((res => {// 处理兑现results[index] = { status: FULFILLED, value: res }count++count === promises.length && reslove(results)}, err => {results[index] = { status: REJECTED, reason: err }count++count === promises.length && reslove(results)}))})})}static any(promises) {return new wePromise((reslove, reject) => {// 判断是否为数组if (!Array.isArray(promises)) {return reject(new TypeError('Argument is not iterable'))}// 空数组直接拒绝promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))// 等待结果const errors = []let count = 0promises.forEach((p, index) => {wePromise.reslove(p).then(res => {// 第一个兑现reslove(res)}, err => {// 全部拒绝errors === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))})})})}}function reslovePromise(p2, x, reslove, reject) {// 处理重复引用if (x === p2) {// 抛出错误throw new TypeError('Chaining cycle detected for promise #<Promise>')}// 处理返回的Promiseif (x instanceof wePromise) {// 调用then方法x.then(res => reslove(res), err => reject(err))} else {// 处理返回值reslove(x)}}// 创建对象,调用两个方法const p = new wePromise((reslove, reject) => {// reslove('success')// reject('reject')throw 'throw-error'})p.then(res => {console.log('成功回调1:', res);// throw 'throw-error'// return 2}).catch(err => {console.log('失败回调1:', err);}).finally(() => {console.log('finally');})</script>
</body>
运行效果
这里运行效果请复制代码自己测,实例方法和静态方法已经是全部实现了的。
三:总结
Promise 是异步编程的一种解决方案,其在工作的项目开发中是非常常用的,熟练的掌握Promise 的内容,熟悉底层源码,可以让我们在项目开发中具备更高超的代码书写能力,同时降低自己在使用Promise 出现的各种bug。好啦,Promise 源码系列到此就算是结束啦,希望能够对各位小伙伴有所帮助哦!