手撕一个Promise详细过程
面试官问你Promise原理,以及让你手写一个Promise并实现其中的then()
、catch()
等方法,不用呆在原地了😛,下面是我手撕Promise的过程以及一些心得,在手撕Promise之前你得知道什么是Promise
以及Promise
如何使用,如果有不是很熟悉的可以去看我之前写的面试系列二中的Promise
前端面试题目系列二💨
其实Promsie
的手写过程不是很难,大家自己动手理清思路和重要,下面是我手写Promise的源码,就实现了一些常用Promise的方法,所有的测试都能跑通,XDM放心食用,更详细的讲解放在最后了!!!
// 抽取封装函数
function resolvePromise(promiseExmpl, x, resolve, reject) {
if(x === promiseExmpl) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
x instanceof NewPromise ? x.then(res => resolve(res), error => reject(error)) : resolve(x)
}
//定义一个枚举对象来表示 Promise 的三种状态
const Status = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
// 1.0 定义类
class NewPromise {
status = Status.PENDING
value = null //成功时的值
reason = null //失败时的原因
onFulfilledCallbacks = [] //存储成功时候的回调
onRejectedCallbacks = [] //存储失败时候的回调
constructor(fn) {
const resolve = (value) => {
if(this.status === Status.PENDING) {
this.status = Status.FULFILLED
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
const reject = (reason) => {
if (this.status === Status.PENDING) {
this.status = Status.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
try {
fn(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; }
const promiseExmpl = new NewPromise((resolve, reject) => {
if(this.status === Status.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
reject(error)
}
},0)
}
if(this.status === Status.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
reject(error)
}
},0)
}
if(this.status === Status.PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promiseExmpl, x. resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
return promiseExmpl
}
catch(onRejected) {
return this.then(null, onRejected)
}
}
手写Promise过程以及测试代码
/**
* 核心步骤:
* 1.构造函数
* 1.0 定义类
* 1.1 添加构造函数
* 1.2 定义resolve/reject方法
* 1.3 执行回调函数
* 2.状态及原因
* 2.1 添加状态 (status)
* 2.2 添加成功值和失败原因 (value、reason)
* 2.3 调整resolve/reject函数
* 2.4 状态不可逆(指状态只能从Pending到达某一状态,不能从fulfilled到达rejected,反之亦然)
* 3.then方法实现
* 3.1 添加实例方法
* 3.2参数判断(MDN文档中有说明 Promise.Prototype.then())
* 3.2.1 执行成功回调
* 3.2.2 执行失败回调
* 3.3 支持异步及多次调用
* 3.3.1 定义存储成功和失败的回调的实例属性
* 3.3.2 保存then中的回调函数
* 3.3.3 调用成功回调
* 3.3.4 调用失败回调
* 4.异步任务
* 4.1 使用 setTimeout 来实现 Promise 可以确保 resolve 和 reject 的调用是在宏任务队列中执行的
* 5.链式调用
* 5.1 返回新的Promise实例
* 5.2 获取返回值
* 5.2.1 处理返回值
* 5.2.2 处理异常
* 5.2.3 处理返回的Promise(调用then方法)
* 5.2.4 处理重复引用
* 6.catch方法实现
* 6.1 内部调用then方法
* 6.2 异常处理
*/
// 抽取封装函数
function resolvePromise(promiseExmpl, x, resolve, reject) {
//5.2.4 处理重复引用
if(x === promiseExmpl) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
// 5.2.1 处理返回值
// 5.2.3 处理返回的Promise(调用then方法)
x instanceof NewPromise ? x.then(res => resolve(res), error => reject(error)) : resolve(x)
}
//定义一个枚举对象来表示 Promise 的三种状态
const Status = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
// 1.0 定义类
class NewPromise {
// 2.1 添加状态
status = Status.PENDING
// 2.2 添加原因
value = null //成功时的值
reason = null //失败时的原因
// 3.3.1 定义存储成功和失败的回调的实例属性
onFulfilledCallbacks = [] //存储成功时候的回调
onRejectedCallbacks = [] //存储失败时候的回调
//构造函数就是newPromise的参数,即是一个回调函数,回调函数中的参数分别是resolve函数和reject函数
// 1.1 添加构造函数
constructor(fn) {
// 1.2 resolve函数的实现
const resolve = (value) => {
// 2.4 状态不可逆
if(this.status === Status.PENDING) {
// 2.3 调整resolve函数,改变状态 pengding ---> fulfilled
this.status = Status.FULFILLED
this.value = value
// 3.3.3 调用回调任务队列中的成功回调
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
// 1.2 reject函数的实现
// 2.3 调整reject函数,改变状态 Pengding ---> rejected
const reject = (reason) => {
// 2.4 状态不可逆
if (this.status === Status.PENDING) {
// 2.3 调整resolve函数,改变状态 pengding ---> fulfilled
this.status = Status.REJECTED
this.reason = reason
// 3.3.4 调用失败回调
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
// 6.2 异常处理
try {
// 1.3 执行回调函数
fn(resolve, reject)
} catch (error) {
reject(error)
}
}
// 3.1 添加实例方法
then(onFulfilled, onRejected) {
// 3.2参数判断
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; }
//5.1 返回新的Promise实例
const promiseExmpl = new NewPromise((resolve, reject) => {
// 5.2 获取返回值,这个返回值是是一个then方法中成功的回调函数的返回值,即onFulfilled()的返回值
//第二个.then()方法其实是这个返回的新的Promise实例的
//关键点:Promise传入的回调函数会立即执行
// 3.2.1 执行成功回调
if(this.status === Status.FULFILLED) {
// Promise实例中resolve()的值是then方法中成功回调函数的参数
//onFulfilled(this.value) === 实例对象promise中then方法中成功的回调(res) => { }
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
// 5.2.2 处理异常
reject(error)
}
},0)
}
// 3.2.1 执行失败回调
if(this.status === Status.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
reject(error)
}
},0)
}
if(this.status === Status.PENDING) {
// 3.3.2 保存then中的回调函数
this.onFulfilledCallbacks.push(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promiseExmpl, x, resolve, reject)
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promiseExmpl, x. resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
return promiseExmpl
}
// 6. 实现catch方法(用then方法实现catch方法,有疑惑的可以看我之前前端面试题目Promise)
catch(onRejected) {
return this.then(null, onRejected)
}
}
// --------------------测试代码-------------------
console.log("top")
const promise = new NewPromise((resolve, reject) => {
// setTimeout(() => {
// resolve("success")
// // reject('error222')
// },2000)
// console.log('1111111');
resolve("success") //Pengding ---> fulfilled
// reject("error111") //Pengding ---> rejected
//throw 'new error'
})
//支持链式编程
promise.then(res => {
// 这个成功回调函数的返回的值就是onFulfilled()的返回值
console.log('成功回调then1:', res)
//return 2
// throw 'error eor'
return new NewPromise((resolve, reject) => {
resolve(3)
// reject('error')
// setTimeout(() => {
// resolve(4)
// },2000)
})
}).then(res => {
console.log("成功回调then2:", res)
},error => {
console.log("失败回调error2:", error)
})
//cath方法捕获rejectd的错误以及主动抛出的错误
// promise.then(res => {
// console.log('成功的回调:', res)
// }).catch(error => {
// console.log("错误捕获:", error)
// })
//原生Promise会有这个重复引用的问题,而新手写的Promise没有这个错误
//TypeError: Chaining cycle detected for promise #<Promise>
// const p2 = promise.then(res => {
// return p2
// })
// p2.then(res => {}, error => {
// console.log("重复引用错误:", error)
// })
//多次调用测试
// promise.then(res => {
// console.log('成功回调then2:', res)
// },err => {
// console.log("失败回调error2:", err)
// })
console.log("bottom")
我自己在写的过程中也出现了很多bug,最后都顺利解决了,下面这些图片可能会帮助你们理解上面的代码