持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
前言
大家好,我是小阵 🔥,一路奔波不停的码字业务员
身为一个前端小菜鸟,总是有一个飞高飞远的梦想,因此,每点小成长,我都想要让它变得更有意义,为了自己,也为了更多值得的人
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~😋
加我微信:zzz886885,邀你进群,一起学习交流,摸鱼学习两不误🌟
开开心心学技术大法~~
来了来了,他真的来了~
正文
分析promise
- promise内部有状态promiseStatus
- fulfiled 成功状态
- rejected 失败状态
- pending 等待状态
- promiseStatus状态只有第一次生效
- pending变为resolve之后不会再次变为reject或pending
- pending变为reject之后不会再次变为resolve或pending
- promise内部有结果promiseResult
- 初始值是null
- 成功时是resolve传入的结果
- 失败时是error或reject传入的结果
- promise有resolve和reject
- resolve触发才表示promise成功,并且可以往下走
- promise内部有错误触发reject,终止执行
- promise有then
- then中可传入新的resolve和reject
- then之后返回一个promise
- then可以链式调用
- 当promise中有异步任务时依然可以按照顺序链式执行then
- promise是微任务
具体实现
从定义属性开始
class myPromise {
constructor(executor) {
this.initValue()
this.initBind()
executor(this.resolve, this.reject)
}
initValue() {
this.promiseResult = null;
this.promiseStatus = 'pending';
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
this.then = this.then.bind(this)
}
resolve(res) {
this.promiseResult = res;
this.promiseStatus = 'fulfilled'
}
reject(err) {
this.promiseResult = err;
this.promiseStatus = 'rejected'
}
then(resolve, reject) {
const thenPromise = new myPromise((_resolve, _reject) => {
if (this.promiseStatus === 'fulfilled') {
resolvePromise(resolve)
} else if (this.promiseStatus === 'rejected') {
resolvePromise(reject)
}
return thenPromise;
}
}
上面我们做了哪些事情?
-
在new myPromise的时候将callback拿到并且立即实行,并且将myPromise内部的resolve和reject传入到callback中。
-
初始化myPromise内部的promiseResult和promiseStatus。
-
绑定resolve和reject、then的this,这个很重要,因为会涉及到then的链式调用,所以绑定this至关重要,也可以避免一些this指向的问题
promise状态只能改变一次
因为promise的状态只能被改变一次,因此需要在resolve和reject中添加校验逻辑
if (this.promiseStatus !== 'pending') return;
只有从pending转变成其他状态时才往下执行,否则直接return
promsie内部报错,直接reject
try {
executor(this.resolve, this.reject)
// executor.call(this, this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
promise支持异步调用
promise内部可执行异步代码且then能保持链式执行。思考一下,我们new出来的实例上一旦挂在then函数,那我们是不是就直接可以拿到这个方法,我们将方法存储在myPromise内部,当resolve导致的promiseResult和promsieStatus变化之后再执行之前存储起来的方法不就可以了吗?
另外,因为之后要支持then的链式调用,因此建议通过数组来存储方法
这里需要补充一点,尽管then被存到了数组中,但是数组中只会有一个then方法,那其他链式调用的then被挂到哪里去了呢?思考一下,每一个then都会返回一个新的promise,那当然新promise的then会挂到这个新的promise上啦。所以通过数组或对象来存储都可以,具体看个人
initValue() {
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
}
then(resolve, reject) {
const thenPromise = new myPromise((_resolve, _reject) => {
if (this.promiseStatus === 'fulfilled') {
resolvePromise(resolve)
} else if (this.promiseStatus === 'rejected') {
resolvePromise(reject)
} else {
this.fulfilledCallbacks.push(resolve)
this.rejectedCallbacks.push(reject)
}
return thenPromise;
}
promise的then链式调用
链式调用的关键是this。
首先我们应该明白,then方法返回一个promise,返回的promise保存下一个then的callback,然后通过callback继续返回一个新的promise。
其中在每一个then方法中,this都应该指向前面的promise,只有如此,才可以在then方法体中安全的拿到promiseStatus和promiseResult。
同时又因为then方法体返回的promise中保存有下一个then的callback,也就是新的resole和reject,所以可以在由本次then来判定如何在合适的实际调用新的resolve和reject。
从而一层层嵌套下去。
then(resolve, reject) {
// 这里的this是外层promise的this,无需多言
// 这个resolve是本次then的resolve
const resolveCallback = resolve;
// 这个promise里的resolve是本次then之后返回的promise里的resolve
// 也就是是本次then之后then的callback
const thenPromise = new myPromise((_resolve, _reject) => {
// 这里的this依然是外层promise的this,因为箭头函数自动绑定this
// 或者写成 (function(_resolve,_reject){}).bind(this)
const resolvePromise = (cb) => {
// 这里的this依然还是是外层promise的this,因为箭头函数自动定义函数时外部的this,针对执行resolvePromise时this变化的情况
try {
const t = cb(this.promiseResult)
if (t instanceof myPromise) {
// 说明返回的是myPromise
t.then(_resolve, _reject)
} else {
_resolve(t)
}
} catch (err) {
// 如果then中传入的resolve方法体中有报错,则先执行本次then的reject
reject(err)
// 然后再触发下一个then的catch
_reject(err)
// throw new Error(err)
}
}
if (this.promiseStatus === 'fulfilled') {
resolvePromise(resolveCallback)
} else if (this.promiseStatus === 'rejected') {
resolvePromise(reject)
} else {
// 这里的关键不是bind this(当然,前提是前面resolvePromise要是箭头函数,或者已经手动绑定过this了),而是既要将resolveCallback或reject传入resovlePromise,又要不执行
// 我们尝试了以下三种写法,都是没问题的,我们随便用一种写法
// 思考以下,为什么不bind this的情况下,this依然可以指到外层promise?
// 因为resolvePromise(xx)被传入到数组中,真正执行时依然是在外层promise的resolve中,所以这个时候this依然执行外层promise
// this.fulfilledCallbacks.push(function () { resolvePromise(resolveCallback) })
// this.fulfilledCallbacks.push(() => resolvePromise(resolveCallback))
this.fulfilledCallbacks.push(resolvePromise.bind(this, resolveCallback))
// this.rejectedCallbacks.push(resolvePromise.bind(this, reject))
// this.rejectedCallbacks.push(pushFn)
this.rejectedCallbacks.push(function () { resolvePromise(reject) })
}
})
return thenPromise;
}
}
因为then方法是promise实现的关键,所有我补充了很多注释,不懂的小伙伴可以自己写一遍,才可以更深刻的理解到。
享受成果
console.log('11')
const test = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve('是是是')
}, 1000)
})
.then((res) => {
console.log('第一个then的打印', res)
// throw('sdd')
// return {}
return 1
})
.then(
function (res) {
console.log('第二个then的打印', res)
// return 2
// throw ('第二个then的throw')
return new myPromise((resolve, reject) => {
// reject('错误')
setTimeout(() => {
resolve('我是第二个then的promiseResult')
}, 1000);
})
},
err => console.log('我是第二个then的catch', err)
)
.then(
function (res) {
console.log('我是第三个then的打印', res)
reject('错误')
},
err => console.log('我是第三个then的catch', err)
)
.then(
res => {
console.log('我是第四个then的打印', res)
},
err => console.log('我是第四个catch', err)
)
// console.log(test)
console.log('22')
结语
往期好文推荐「我不推荐下,大家可能就错过了史上最牛逼vscode插件集合啦!!!(嘎嘎嘎~)😄」