前言
Promise MDN,理论知识点就跳过了,MDN或者图灵社区文档介绍的都很详细,我们今天就来动动小手实践一下如何实现一个自己的 MiniPromise
进入主题
首先来看看一个常规的 Promsie 是怎么使用的 ?
new Promise((resolve,reject) => {
setTimeout(() => {
resolve("hellow promise")
},1000)
}).then(res => {
console.log(`成功 ${res}`)
},error => {
console.log(`失败 ${error}`)
})
Promise {<pending>}
VM696:6 成功 hellow promise // 1s 后打印
接下来我们把它分解一下,然后来动动小手实践实践
- promise 函数
new Promise((resolve,reject) => {
resolve("hellow promise")
})
- 成功与失败回调
.then(res => {
console.log(`成功 ${res}`)
},error => {
console.log(`失败 ${error}`)
})
实现一个 Promise 函数
分析 - 当然也可以通过官网介绍了解
- 首先通过
new Promise( () => {} )可以看出来它是一个构造函数,并且接受一个函数 - 通过
(resolve,reject) => {}可以知道该函数接受两个参数,成功和失败的回调 - 当我们
new Promise()的时候会自动调用传入的参数(即 1 中的函数)
好,简单的分析之后,来代码实践一下
class MyPromise {
constructor (executor) {
// 判断一下 executor 的类型,因为要求是一个函数
if(typeof executor !== "function") {
console.log(`${executor} 不是一个函数`)
return
}
console.log('进来了')
// 定义成功和失败的回到函数
const resolve = () => {} // 成功操作
const reject = () => {} // 失败操作
// executor 调用,传入成功和失败的回调函数
executor(resolve,reject)
}
}
测试
new MyPromise(123)
VM1390:5 123 不是一个函数
MyPromise {}
new MyPromise((resolve,reject) => {})
VM1390:8 进来了
MyPromise {}
看起来是那么回事儿哈,接着往下走
分析
new Promise((resolve,reject) => {
resolve("hellow promise")
// reject("我错了")
})
- 执行
executor函数,我们会传入 resolve || reject 函数 - 那么它们的执行时机是什么 ? 状态 state 分三种
pendding 等待 | fuldilled 成功 | rejected 失败 - resolve || reject 函数依赖 state 状态执行,并且接收成功值和失败原因
所以我们需要定义三个变量,分别是 状态 state , 成功值 value , 失败原因 error
class MyPromise {
constructor (executor) {
// 判断一下 executor 的类型,因为要求是一个函数
if(typeof executor !== "function") {
console.log(`${executor} 不是一个函数`)
return
}
console.log('进来了')
this.state = "pendding" // 状态
this.value = "" // 成功值
this.error = "" // 失败原因
// 定义成功和失败的回到函数
const resolve = (value) => {
if(this.state === "pendding"){
this.state = "fulfilled"
this.value = value;
}
} // 成功操作
const reject = (error) => {
if(this.state === "pendding"){
this.state = "rejected"
this.error == error
}
} // 失败操作
// executor 调用,传入成功和失败的回调函数
executor(resolve,reject)
}
}
测试
new MyPromise((resolve,reject) => {resolve("hellow promise")})
VM1894:8 进来了
MyPromise {state: "fulfilled", value: "hellow promise", error: ""}
成功与失败回调
分析
.then(res => {
console.log(`成功 ${res}`)
},error => {
console.log(`失败 ${error}`)
})
- then 方法接收两个参数分别是成功回调和失败回调 onFulfilled | onRejected
- onFulfilled | onRejected 分别接收构造函数的成功值
velue和失败原因error - 扩展:如果 then 接收的不是函数怎么办 ?
constructor (executor) {
// 判断一下 executor 的类型,因为要求是一个函数
if(typeof executor !== "function") {
console.log(`${executor} 不是一个函数`)
return
}
console.log('进来了')
this.state = "pendding"
this.value = ""
this.reason = ""
// 定义成功和失败的回到函数
const resolve = (value) => {
if(this.state === "pendding"){
this.state = "fulfilled"
this.value = value;
}
} // 成功操作
const reject = (error) => {
if(this.state === "pendding"){
this.state = "rejected"
this.reason == error
}
} // 失败操作
// executor 调用,传入成功和失败的回调函数
executor(resolve,reject)
}
// then
then (onFulfilled,onRejected) {
// 类型校验,重要,不是一个函数,则包裹成函数返回, 做个铺垫,方便后续链式调用
if(typeof onFulfilled !== "function") {
onFulfilled = function (value) {
return value
}
}
if(typeof onRejected !== "function") {
onRejected = function (error) {
throw error
}
}
// 调用
if(this.state == "fulfilled") {
onFulfilled(this.value)
}
if(this.state == "rejected") {
onFulfilled(this.error)
}
}
}
测试
new MyPromise((resolve,reject) => {
resolve("hellow promise")
}).then(
res => {
console.log(`then : ${res}`)
},
error => {
console.log(error)
}
)
VM2672:8 进来了
VM2889:2 then : hellow promise
截止到这里,感觉有那么点儿意思,貌似基本实现了一个 Promise , 然而事实真的是这样嘛 ? 都知道 promise 是 Js 异步编程解决方案,我悄然的写下一段测试代码,结果 emmm ~~
console.log(1)
new MyPromise((resolve,reject) => {
console.log(2)
resolve(3)
}).then(res => {
console.log(res)
})
console.log(4)
VM3481:1 1
VM3481:3 2
VM3481:6 3
VM3481:8 4
打印结果居然是 1,2,3,4 , 这不符合逻辑呀,按照 eventloop 事件循环 promise 的 then 是异步微任务 结果不是应该 1,2,4,3 嘛 ? 回头一看,阿西巴,我哪里写过异步处理 ? 风风火火的优化一版,在执行回调的时候使用 setTimeout 包裹一下
class MyPromise {
constructor (executor) {
// 判断一下 executor 的类型,因为要求是一个函数
if(typeof executor !== "function") {
console.log(`${executor} 不是一个函数`)
return
}
console.log('进来了')
this.state = "pendding"
this.value = ""
this.reason = ""
// 定义成功和失败的回到函数
const resolve = (value) => {
if(this.state === "pendding"){
this.state = "fulfilled"
this.value = value;
}
} // 成功操作
const reject = (error) => {
if(this.state === "pendding"){
this.state = "rejected"
this.reason == error
}
} // 失败操作
// executor 调用,传入成功和失败的回调函数
executor(resolve,reject)
}
// then
then (onFulfilled,onRejected) {
// 类型校验
if(typeof onFulfilled !== "function") {
onFulfilled = function (value) {
return value
}
}
if(typeof onRejected !== "function") {
onRejected = function (error) {
throw error
}
}
// 调用
if(this.state == "fulfilled") {
setTimeout(() => {
onFulfilled(this.value)
})
}
if(this.state == "rejected") {
setTimeout(() => {
onFulfilled(this.error)
})
}
}
}
测试
VM3584:1 1
VM3584:3 2
VM3584:8 4
VM3584:6 3
嗯,是这个样子,然后我又默默的按照常规逻辑写一个异步测试,结果再次 emmm ~~
console.log(1)
new MyPromise((resolve,reject) => {
console.log(2)
setTimeout(() => {
resolve(3)
},1000)
}).then(res => {
console.log(res)
})
VM3660:1 1
VM3660:3 2
没打印 3 什么逻辑,经过一番调试,发现当代码执行走进MyPromise构造函数执行setTimeout的时候是异步任务,然后直接往下执行走到 then, 此时进入 then 方法, state 状态为 pendding 所以没做任何事儿,因为我上边只针对状态为 fulfilled | rejected 做了处理,索嘎 ~ 风风火火又优化了一把
逻辑
- 进入
then方法,状态为pendding时,将成功和失败回调存储起来 - 当状态变更为
fulfilled | rejected时拿到存储的回调函数执行
class MyPromise {
constructor (executor) {
// 判断一下 executor 的类型,因为要求是一个函数
if(typeof executor !== "function") {
console.log(`${executor} 不是一个函数`)
return
}
console.log('进来了')
this.state = "pendding"
this.value = ""
this.reason = ""
this.onFulfilledCallbacks = [] // 成功回到函数存储
this.onRejectedCallbacks = [] // 失败回调函数存储
// 定义成功和失败的回到函数
const resolve = (value) => {
if(this.state === "pendding"){
this.state = "fulfilled"
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn(value)) // 异步调用
}
} // 成功操作
const reject = (error) => {
if(this.state === "pendding"){
this.state = "rejected"
this.reason == error
this.onRejectedCallbacks.forEach(fn => fn(value)) // 异步调用
}
} // 失败操作
// executor 调用,传入成功和失败的回调函数
executor(resolve,reject)
}
// then
then (onFulfilled,onRejected) {
// 类型校验
if(typeof onFulfilled !== "function") {
onFulfilled = function (value) {
return value
}
}
if(typeof onRejected !== "function") {
onRejected = function (error) {
throw error
}
}
// 调用
if(this.state == "fulfilled") {
setTimeout(() => {
onFulfilled(this.value)
})
}
if(this.state == "rejected") {
setTimeout(() => {
onFulfilled(this.error)
})
}
// state === "pendding" 存储回调函数, 成功和失败同理
if(this.state === "pendding"){
this.onFulfilledCallbacks.push(value => {
setTimeout(() => {
onFulfilled(value)
})
})
this.onRejectedCallbacks.push(value => {
setTimeout(() => {
onFulfilled(value)
})
})
}
}
}
测试
console.log(1)
new MyPromise((resolve,reject) => {
console.log(2)
setTimeout(() => {
resolve(3)
},1000)
}).then(res => {
console.log(res)
})
console.log(4)
VM4533:1 1
VM4533:3 2
VM4533:11 4
VM4533:9 3
终于 MyPromise 可以了,都知道 Promise 的优势在于它可以链式调用,那么又是怎么实现的呢 ? 思考:要想实现链式调用,就得返回实例本身,可是 Promise 的状态不可逆,且回调只可调用一次,怎么办, 其实它是包裹了一个新的 Promise 实例,且等我下次分解,追加
小小鼓励,大大成长,欢迎点赞