一文学会手写Promise
什么是Promise
在开始编码之前,我们先来看一下什么是Promise,话不多说直接上MDN的描述。
看完MDN的描述我们已经知道Promise原来是一个对象,可以表示异步操作的成功或失败。
PromiseA+规范
Promise的实现要符合PromiseA+规范,那我们就先看一下什么是PromiseA+规范。
从规范中我们了解到,promise是一个对象,要包含一个then方法。具体的内容感兴趣的可以去 原文 了解一下。
开始动手了
// 定义promise状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
/**
* 创建MyPromise类
*/
class MyPromise {
/**
* 接受一个执行器
* @param { function } executor
*/
constructor(executor){
// 默认状态为pending
this.state = PENDING
this.value = undefined
executor(this._resolve.bind(this),this._reject.bind(this))
}
/**
* 更改promise状态为成功
* @param {*} data
*/
_resolve(data) {
this.state = FULFILLED
this.value = data
}
/**
* 更改状态为失败
* @param {*} reason
*/
_reject(reason) {
this.state = REJECTED
this.value = reason
}
}
我们已经可以通过MyPromise这个类来创建promise实例了,接下来我们实现then方法并完善一下这个类。
/**
* 创建MyPromise类
*/
class MyPromise {
/**
* 接受一个执行器
* @param { function } executor
*/
constructor(executor){
// 默认状态为pending
this.state = PENDING
this.value = undefined
this.handlers = []
executor(this._resolve.bind(this),this._reject.bind(this))
}
/**
* 变更状态的方法
*/
_changeState(state,value) {
if(this.state!==PENDING) { return }
this.state = state
this.value = value
}
/**
* 往任务队列添加任务
*/
_pushHandler(executor,state,resolve,reject){
this.handlers.push({
executor,state,resolve,reject
})
}
/**
* 更改promise状态为成功
* @param {*} data
*/
_resolve(data) {
this._changeState(FULFILLED,data)
}
/**
* 更改状态为失败
* @param {*} reason
*/
_reject(reason) {
this._changeState(REJECTED, reason)
}
/**
* 符合Promise A+规范的then方法
*/
then(onFulfilled,onRejected){
// then方法返回一个promise执行
return new MyPromise((resolve,reject) => {
this._pushHandler(onFulfilled,FULFILLED,resolve,reject)
this._pushHandler(onRejected,REJECTED,resolve,reject)
})
}
}
ok,then方法已经添加了,现在已经可以把任务添加到存储任务的数组了,你是不不是以为这就大功告成了。NONONO,我们还少了最重要的一步,任务的执行。说到任务的执行,那就离不了宏任务和微任务的概念了,让我们先来看一下什么是宏任务和微任务吧。
宏任务与微任务
我们学习js听的最多的一句话应该就是js是单线程执行了。那既然是单线程执行遇到比较耗时的任务时怎么处理呢,总不能一直阻塞吧。为了解决这个问题,js划分了同步任务和异步任务。异步任务又分为宏任务和微任务。 常见的任务创建方式:
- 宏任务: script(整体代码块)、settimeout、setInterval、setImmediate(node环境)
- 微任务:MutationObserver(浏览器环境)、 process.nextTick(node环境)、queueMicrotask
这里对异步机制介绍的比较粗陋,感兴趣的同学可以移步 js执行机制去了更多。
实现任务执行
我们先来写一个执行微任务的辅助函数和一个判断是否是promise的函数
/**
* 接收一个函数放入微队列执行
* @param { function } callback
*/
function runMincroTask(callback) {
if(queueMicrotask) {
queueMicrotask(callback)
} else if(process&&process.nextTick){
process.nextTick(callback)
} else if(MutationObserver){
let p = document.createElement('p')
const ob = new MutationObserver(callback)
ob.observe({
childList: true
})
p.innerHTML = '1'
} else {
setTimeout(callback,0)
}
}
/**
* 接受一个任意参数,判断是否为promise
* @param {*} obj
* @returns
*/
function isPromise(obj) {
return !!(obj&&typeof obj==='object' && typeof obj.then === 'function' )
}
准备工作搞定了,接下来我们来实现任务执行的方法。
/**
* 任务执行方法
*/
_runHandler() {
if(this.state===PENDING) { return }
// 拿出任务队列的每一项执行
while(this.handlers[0]) {
const handle = this.handlers[0]
this._runOneHandler(handle)
this.handlers.shift()
}
}
/**
* 执行任务队列的每一项任务
*/
_runOneHandler({executor,state,resolve,reject}){
// 把任务放入微任务队列执行
runMincroTask(() => {
if(state!==this.state) { return }
if(typeof executor !== 'function') {
this.state === FULFILLED ? resolve(this.value) : reject(this.value)
return
}
try {
const result = executor(this.value)
if(isPromise(result)) {
result.then(resolve,reject)
} else {
resolve(this.value)
}
} catch (error) {
reject(this.value)
console.log(error)
}
})
}
呼~,任务执行的方法搞定了。接下来我们在状态改变和then方法中添加调用。
/**
* 变更状态的方法
*/
_changeState(state,value) {
if(this.state!==PENDING) { return }
this.state = state
this.value = value
// 状态变更调用任务执行
this._runHandler()
}
then(onFulfilled,onRejected){
// then方法返回一个promise执行
return new MyPromise((resolve,reject) => {
this._pushHandler(onFulfilled,FULFILLED,resolve,reject)
this._pushHandler(onRejected,REJECTED,resolve,reject)
this._runHandler()
})
}
验证
大功告成,接下来我们来验证是否好使吧。
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 1000)
})
Promise.any([
p,p1
]).then((first) => { // 只要有一个 fetch() 请求成功
console.log(first);
}).catch((error) => { // 所有三个 fetch() 全部请求失败
console.log(error);
});
利用原生Promise 和 MyPromise进行测试,最终结果输出正确。至此一个符合Promise A+规范的 Promise就完成了。
catch方法实现
/**
* 处理任务失败的情况
* @param {*} onRejected
* @returns
*/
catch(onRejected) {
return this.then(null ,onRejected)
}
finally方法实现
/**
* 不论成功或失败都会执行的方法
* @param {*} onSetteld
*/
finally(onSetteld){
return this.then(data => {
onSetteld()
return data
}, reason => {
onSetteld()
throw reason
})
}
resolve和reject方法实现
/**
*
* @param {*} obj 需要转为promise的对象
*/
static resolve(obj) {
return new MyPromise((resolve,reject) => {
if(obj instanceof MyPromise) {
return obj
}
if(isPromise(obj)) {
obj.then(resolve,reject)
} else {
resolve(obj)
}
})
}
/**
* 返回一个状态为被拒绝的promise
* @param {*} reason 失败原因
* @returns
*/
static reject(reason) {
return new MyPromise((resolve,reject) => {
reject(reason)
})
}
all方法实现
/**
* 接受一个具有interator属性的值,
* @param { interator } arr
*/
static all(arr) {
return new MyPromise((resolve, reject) => {
try {
let count = 0
let fulfilledCount = 0
let results = []
for (const item of arr) {
let i = count
count++
MyPromise.resolve(item).then(data => {
fulfilledCount++
results[i] = data
if (count === fulfilledCount) {
resolve(results)
}
}, reject)
}
if (count === 0) {
resolve([])
}
} catch (err) {
reject(err)
}
})
}
allSettled方法实现
/**
* 接受一个包含多个promise的参数
* 所有promise已决后返回结果
* @param { interator } arr
*/
static allSettled(arr) {
return new MyPromise((resolve,reject) => {
let results = []
for (const p of arr) {
results.push( MyPromise.resolve(p).then(
data=> ({ status: FULFILLED, value:data })),
reason => ({ status: REJECTED, reason })
)
}
return MyPromise.all(results)
})
}
race方法实现
/**
* 接受一个包含多个promise的参数
* 返回最先完成的promise结果,不论成功还是失败
* @param { interator } arr
*/
static race(arr) {
return new MyPromise((resolve,reject) => {
for (const item of arr) {
MyPromise.resolve(item).then(resolve,reject)
}
})
}
any方法实现
/**
* 接受一个包含多个promise的参数
* 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
* 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
* @param { interator } arr
*/
static any(arr) {
return new MyPromise((resolve,reject) => {
let rejectCount = 0
let errResults = []
for (const item of arr) {
MyPromise.resolve(item).then(resolve,reason => {
rejectCount++
errResults[rejectCount] = { reason }
if(errResults===arr.length) {
reject(errResults)
}
})
}
if(rejectCount===0) {
resolve([])
}
})
}
全部完结啦!!!!!
贴上完整代码
// 定义promise状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
/**
* 接收一个函数放入微队列执行
* @param { function } callback
*/
function runMincroTask(callback) {
if (queueMicrotask) {
queueMicrotask(callback)
} else if (process && process.nextTick) {
process.nextTick(callback)
} else if (MutationObserver) {
let p = document.createElement('p')
const ob = new MutationObserver(callback)
ob.observe({
childList: true
})
p.innerHTML = '1'
} else {
setTimeout(callback, 0)
}
}
/**
* 接受一个任意参数,判断是否为promise
* @param {*} obj
* @returns
*/
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function')
}
/**
* 创建MyPromise类
*/
class MyPromise {
/**
* 接受一个执行器
* @param { function } executor
*/
constructor(executor) {
// 默认状态为pending
this.state = PENDING
this.value = undefined
this.handlers = []
try {
executor(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
this._reject(error)
console.log(error)
}
}
/**
* 变更状态的方法
*/
_changeState(state, value) {
if (this.state !== PENDING) { return }
this.state = state
this.value = value
// 状态变更调用任务执行
this._runHandler()
}
/**
* 往任务队列添加任务
*/
_pushHandler(executor, state, resolve, reject) {
this.handlers.push({
executor, state, resolve, reject
})
}
/**
* 任务执行方法
*/
_runHandler() {
if (this.state === PENDING) { return }
// 拿出任务队列的每一项执行
while (this.handlers[0]) {
const handle = this.handlers[0]
this._runOneHandler(handle)
this.handlers.shift()
}
}
/**
* 执行任务队列的每一项任务
*/
_runOneHandler({ executor, state, resolve, reject }) {
// 把任务放入微任务队列执行
runMincroTask(() => {
if (state !== this.state) { return }
if (typeof executor !== 'function') {
this.state === FULFILLED ? resolve(this.value) : reject(this.value)
return
}
try {
const result = executor(this.value)
if (isPromise(result)) {
result.then(resolve, reject)
} else {
resolve(this.value)
}
} catch (error) {
reject(this.value)
console.log(error)
}
})
}
/**
* 更改promise状态为成功
* @param {*} data
*/
_resolve(data) {
this._changeState(FULFILLED, data)
}
/**
* 更改状态为失败
* @param {*} reason
*/
_reject(reason) {
this._changeState(REJECTED, reason)
}
/**
* 符合Promise A+规范的then方法
*/
then(onFulfilled, onRejected) {
// then方法返回一个promise执行
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject)
this._pushHandler(onRejected, REJECTED, resolve, reject)
this._runHandler()
})
}
/**
* 处理任务失败的情况
* @param {*} onRejected
* @returns
*/
catch(onRejected) {
return this.then(null, onRejected)
}
/**
* 不论成功或失败都会执行的方法
* @param {*} onSetteld
*/
finally(onSetteld) {
return this.then(data => {
onSetteld()
return data
}, reason => {
onSetteld()
throw reason
})
}
/**
*
* @param {*} obj 需要转为promise的对象
*/
static resolve(obj) {
return new MyPromise((resolve, reject) => {
if (obj instanceof MyPromise) {
return obj
}
if (isPromise(obj)) {
obj.then(resolve, reject)
} else {
resolve(obj)
}
})
}
/**
* 返回一个状态为被拒绝的promise
* @param {*} reason 失败原因
* @returns
*/
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
/**
* 接受一个具有interator属性的值,
* @param { interator } arr
*/
static all(arr) {
return new MyPromise((resolve, reject) => {
try {
let count = 0
let fulfilledCount = 0
let results = []
for (const item of arr) {
let i = count
count++
MyPromise.resolve(item).then(data => {
fulfilledCount++
results[i] = data
if (count === fulfilledCount) {
resolve(results)
}
}, reject)
}
if (count === 0) {
resolve([])
}
} catch (err) {
reject(err)
}
})
}
/**
* 接受一个包含多个promise的参数
* 所有promise已决后返回结果
* @param { interator } arr
*/
static allSettled(arr) {
return new MyPromise((resolve,reject) => {
let results = []
for (const p of arr) {
results.push( MyPromise.resolve(p).then(
data=> ({ status: FULFILLED, value:data })),
reason => ({ status: REJECTED, reason })
)
}
return MyPromise.all(results)
})
}
/**
* 接受一个包含多个promise的参数
* 返回最先完成的promise结果,不论成功还是失败
* @param { interator } arr
*/
static race(arr) {
return new MyPromise((resolve,reject) => {
for (const item of arr) {
MyPromise.resolve(item).then(resolve,reject)
}
})
}
/**
* 接受一个包含多个promise的参数
* 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
* 如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
* @param { interator } arr
*/
static any(arr) {
return new MyPromise((resolve,reject) => {
let rejectCount = 0
let errResults = []
for (const item of arr) {
MyPromise.resolve(item).then(resolve,reason => {
rejectCount++
errResults[rejectCount] = { reason }
if(errResults===arr.length) {
reject(errResults)
}
})
}
if(rejectCount===0) {
resolve([])
}
})
}
}
转载自:https://juejin.cn/post/7265329025899855927