赞
踩
首先要实现 Promise
就要让我们了解它具体功能
let p1 = new Promise((resolve)=>{ resolve(2) }) console.log(p1); let p2 = new Promise((resolve,reject)=>{ reject('shibai') }) console.log(p2); let p3 = new Promise((resolve,reject)=>{ err }) console.log(p3); let p4 = new Promise((resolve,reject)=>{ }) console.log(p4);
输出结果:
可以看到我们的主要功能是:
一开是
Promise
的状态为pending
等于未处理状态1、执行了
resolve
,Promise状态会变成fulfilled
2、执行了
reject
,Promise状态会变成rejected
3、Promise只以
第一次为准
,第一次成功就永久
为fulfilled
,第一次失败就永远状态为rejected
4、Promise中有
throw
或者出现语法错误的话,就相当于执行了reject
接下来就按着这个思路一步一步的实现
首先注意首次调用 new Promise 时应该是初始化状态,
并传进一个可含有 resolve
,与 reject
两个参数 的函数
参数在构造函数内调用实现对应功能,
并且注意:函数使用箭头函数的形式来确保对应 this
为该实例对象
class MyPromise{ constructor(excutor){ // 初始化参数 this.initValue() // 执行对应方法 excutor(this.resolve,this.reject) } // 初始化函数,初始状态与值 // 使用箭头函数使this指向实例对象 initValue = () =>{ this.PromiseState = 'pending' this.PromiseResult = null } // resolve 方法 resolve = (value) =>{ this.PromiseState = 'fulfilled' this.PromiseResult = value } // reject 方法 reject = (reason) =>{ this.PromiseState = 'rejected' this.PromiseResult = reason } } // 测试代码 let p1 = new MyPromise((resolve,reject)=>{ resolve('成功') }) console.log(p1); // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' } let p2 = new MyPromise((resolve,reject)=>{ reject('失败') }) console.log(p2); // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }
输出结果:
上述代码有一个问题
let p1 = new MyPromise((resolve,reject)=>{
resolve('成功')
reject('失败')
})
console.log(p1); // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }
为什么会这样呢?
实际上在对于已经执行过的 resolve
或 reject
我们就应该终止执行,而不是再执行下一次 resolve
或 reject
代码实现起来也很简单:
// resolve 方法 resolve = (value) =>{ /*--------------------------------------代码变更----------------------------------------------------------------*/ // 加这一个判断即可 if(this.PromiseState !== 'pending') return this.PromiseState = 'fulfilled' this.PromiseResult = value } // reject 方法 reject = (reason) =>{ /*--------------------------------------代码变更----------------------------------------------------------------*/ if(this.PromiseState !== 'pending') return this.PromiseState = 'rejected' this.PromiseResult = reason }
再看看结果:
let p1 = new MyPromise((resolve,reject)=>{
resolve('成功')
reject('失败')
})
console.log(p1); // MyPromise { PromiseState: 'fulfiiled', PromiseResult: '成功' }
Promise 的执行者(executor)和 promise 的处理程序(handler)周围有一个“隐式的 try..catch
”。如果发生异常,它(译注:指异常)就会被捕获,并被视为 rejection 进行处理。
故我们要让执行错误 或者 手动抛错的语法,也变成 reject
执行
加个 “隐式的 try..catch
”
constructor(excutor){
// 初始化参数
this.initValue()
// 执行对应方法
try {
excutor(this.resolve,this.reject)
} catch (err) {
this.reject(err.message)
}
看看输出结果:
let p1 = new MyPromise((resolve,reject)=>{
throw Error('错误')
})
console.log(p1); // MyPromise {PromiseState: "rejected", PromiseResult: "错误"}
let p3 = new MyPromise((resolve,reject)=>{
promise() // 一个不存在的函数,会报错
})
console.log(p3); // MyPromise {PromiseState: "rejected", PromiseResult: "promise is not defined"}
在 Promise
中 then
相当于将 resolve
或者 reject
的结果,在一个 成功回调 ,一个 失败回调 中使用
看下日常使用的代码:
// 马上输出 ”成功“ const p1 = new Promise((resolve, reject) => { resolve('成功') }).then(res => console.log(res), err => console.log(err)) // 1秒后输出 ”失败“ const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('失败') }, 1000) }).then(res => console.log(res), err => console.log(err)) // 链式调用 输出 200 const p3 = new Promise((resolve, reject) => { resolve(100) }).then(res => 2 * res, err => console.log(err)) .then(res => console.log(res), err => console.log(err))
可以总结出这几个知识点:
then接收两个回调,一个是
成功回调
,一个是失败回调
当Promise状态为
fulfilled
执行成功回调
,为rejected
执行失败回调
如resolve或reject在定时器里,
则定时器结束后再执行then
then支持
链式调用
,下一次then执行受上一次then返回值的影响
下面咱们就一步一步地去实现他吧
// then 方法回调 then = (onFulfilled,onRejected)=>{ // 首先确保传进来的是函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} //判断promise的状态执行对应回调 if(this.PromiseState === 'fulfilled'){ // 若是成功则执行成功的回调,传入成功的值 onFulfilled(this.PromiseResult) } else if(this.PromiseState === 'rejected'){ // 若是成功则执行成功的回调,传入成功的值 onRejected(this.PromiseResult) } }
让我们看看结果:
let p1 = new MyPromise((resolve,reject)=>{
resolve("成功")
}).then(res=>{
console.log(res); // 成功
})
上面我们已经实现了then
的基本功能。那如果是定时器
情况呢?
就好比下面情况
// 1秒后输出 ”成功“
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 1000)
}).then(res => console.log(res), err => console.log(err))
我们要如何实现,1秒后输出成功呢?
实际上,我们不能控制 .then
then方法的调用的时间,但是我们可以在每次调用时
将 then
方法传的两个回调函数保存起来,待定时间到时后,我们再执行回调
我们要如何判断,什么时候该执行回调呢?
其实很简单!
当定时器结束前,
Promise
状态都是pending
当定时器结束后,会调用
resolve
或者reject
来改变对应Promise
的状态所以当我们监测到状态发生变化时,即定时器结束了调用了
resolve
或者reject
只需要在调用时判断存起来的回调函数是否存在,存在就将回调函数提出来,并执行即可
下面是实现代码:
constructor(excutor){ // 初始化参数 this.initValue() // 执行对应方法 try { excutor(this.resolve,this.reject) } catch (err) { this.reject(err.message) } /*-----------------------------------代码改动部分--------------------------------------------------------*/ // 初始化回调函数 this.onFulfilledSync = [] this.onRejectedSync = [] } // resolve 方法 resolve = (value) =>{ if(this.PromiseState !== 'pending') return this.PromiseState = 'fulfilled' this.PromiseResult = value /*-----------------------------------代码改动部分--------------------------------------------------------*/ // 判断是否有then执行回调 while(this.onFulfilledSync.length){ this.onFulfilledSync.shift()(this.PromiseResult) } } // reject 方法 reject = (reason) =>{ if(this.PromiseState !== 'pending') return this.PromiseState = 'rejected' this.PromiseResult = reason // 判断是否有then执行回调 /*-----------------------------------代码改动部分--------------------------------------------------------*/ while(this.onRejectedSync.length){ this.onRejectedSync.shift()(this.PromiseResult) } } // then 方法回调 then = (onFulfilled,onRejected)=>{ // 首先确保传进来的是函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} //判断promise的状态执行对应回调 if(this.PromiseState === 'fulfilled'){ // 若是成功则执行成功的回调,传入成功的值 onFulfilled(this.PromiseResult) } else if(this.PromiseState === 'rejected'){ // 若是成功则执行成功的回调,传入成功的值 onRejected(this.PromiseResult) } /*-----------------------------------代码改动部分--------------------------------------------------------*/ // 多加了一层判断当定时还没结束时,状态就是pending,那么将回调函数保存起来 else if(this.PromiseState === 'pending') this.onFulfilledSync.push(onFulfilled) this.onRejectedSync.push(onRejected) }
下面看看加了定时器的输出结果吧:
let p1 = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('一秒后输出成功')
},1000)
}).then(res=>{
console.log(res); // 一秒后输出成功
})
then支持链式调用
,下一次then执行受上一次then返回值的影响
,给大家举个例子:
// 链式调用 输出 200 const p3 = new Promise((resolve, reject) => { resolve(100) }).then(res => 2 * res, err => console.log(err)) .then(res => console.log(res), err => console.log(err)) // 链式调用 输出300 const p4 = new Promise((resolve, reject) => { resolve(100) }).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err)) .then(res => console.log(res), err => console.log(err)) // 非promise 链式调用手动抛出错误(类似reject) new Promise((resolve,reject)=>{ resolve('失败') }).then(res=>{ throw res }).then(res=>{console.log(res);},err=>{console.log(err);}) // err 失败回调 处输出'失败' // 非promise 链式调用正常返回值 new Promise((resolve,reject)=>{ reject('失败') }).then(res=>{},err=>err) .then(res=>{console.log(res);},err=>{console.log(err);}) // res 成功回调 处输出'失败'
从上方例子,我们可以获取到几个知识点:
咱们知道then是Promise上的方法,那如何实现then完还能再then呢?
很简单,then执行后返回一个Promise对象
就行了,就能保证then完还能继续执行then:
代码实现:
// then 方法回调 then = (onFulfilled,onRejected)=>{ // 首先确保传进来的是函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} /*----------------------------------------代码改变区域---------------------------------------------------*/ // 创建一个then返回的Promise const thenPromise = new MyPromise((resolve,reject)=>{ // 创建 then 回调函数的执行函数 const resultPromise = cb =>{ // 执行then回调函数,并用try,catch隐式捕捉错误 try { const result = cb(this.PromiseResult) // 如果返回的结果还是promise if(result instanceof MyPromise){ // 要判断它的状态,到底是resolve 还是 reject 只有调用它自身的then方法才得知 // 将要返回的resolve,reject,作为它then的回调,这样就能保持一致的状态 result.then(resolve,reject) } // 如果不是返回的promise else{ resolve(result) } } catch (err) { // 抛出的错误,在此捕获并reject掉 reject(err.message) } } // 开始执行then回调 if(this.PromiseState === 'fulfilled'){ resultPromise(onFulfilled) } else if(this.PromiseState === 'rejected'){ resultPromise(onRejected) } else if(this.PromiseState === 'pending'){ this.onFulfilledSync.push(onFulfilled) this.onRejectedSync.push(onRejected) } }) // 调用then后返回处理果的结果 return thenPromise /*----------------------------------------代码改变区域---------------------------------------------------*/ }
看看最终实现的效果吧:
let p1 = new MyPromise((resolve,reject)=>{
resolve(2)})
.then(res=> res * 2)
.then(res=>{console.log(res)}) // 输出 4 将 res * 2 返回后再输出
let p2 = new MyPromise((resolve,reject)=>{
resolve(2)})
.then(res=> {throw Error('失败')}) // 这里在第一个then里手动reject
.then(res=>{},err=>{console.log(err);}) // 最后也会第二个失败回调里输出 失败
let p3 = new MyPromise((resolve,reject)=>{
resolve(2)})
.then(res=>new MyPromise((resolve,reject)=>reject('promise失败'))) // 通过第一个then返回promise来reject
.then(res=>{},err=>{console.log(err);}) // 最后也会第二个失败回调里输出 romise失败
当你真的搞懂后,就会明白为什么第一个then里成功回调里抛出错误,会在第二个then里失败回调输出
看过js执行机制
的兄弟都知道,then方法是微任务
,啥叫微任务呢?
不理解的可以看之前写的一篇介绍 Promise微任务
其实不知道也不要紧,我通过下面例子让你知道:
const p = new Promise((resolve, reject) => {
console.log(1)
resolve(2)
}).then(res => console.log(res), err => console.log(err))
console.log(3)
输出顺序是 1 3 2
因为then微任务的缘故,故在script执行完后才会执行微任务
所以输出 1 —> 3 —> 2
那我们只需要让 resultPromise函数
异步执行就可以了
const resultPromise = cb =>{ /*------------------------------------在此加上定时器----------------------------------------------------*/ setTimeout(()=>{ // 执行then回调函数,并用try,catch隐式捕捉错误 try { const result = cb(this.PromiseResult) // 如果返回的结果还是promise if(result instanceof MyPromise){ // 要判断它的状态,到底是resolve 还是 reject 只有调用它自身的then方法才得知 // 将要返回的resolve,reject,作为它then的回调,这样就能保持一致的状态 result.then(resolve,reject) } // 如果不是返回的promise else{ resolve(result) } } catch (err) { // 抛出的错误,在此捕获并reject掉 reject(err.message) } }) }
看看输出结果:
const test4 = new MyPromise((resolve, reject) => {
console.log('xxx');
resolve(100)
}).then(res => {
console.log(res);
throw new Error('eee')
}, err => new MyPromise((resolve, reject) => resolve(3 * err)))
.then(res => console.log('成功', res), err => console.log('失败', err))
console.log('sss');
// xxx ---> sss ---> 100 ---> 失败 ,eee
代码最终实现的模板:
class MyPromise{ constructor(excutor){ // 初始化参数 this.initValue() // 执行对应方法 try { excutor(this.resolve,this.reject) } catch (err) { this.reject(err.message) } // 初始化回调函数 this.onFulfilledSync = [] this.onRejectedSync = [] } initValue = () =>{ this.PromiseState = 'pending' this.PromiseResult = null } // resolve 方法 resolve = (value) =>{ if(this.PromiseState !== 'pending') return this.PromiseState = 'fulfilled' this.PromiseResult = value // 判断是否有then执行回调 while(this.onFulfilledSync.length){ this.onFulfilledSync.shift()(this.PromiseResult) } } // reject 方法 reject = (reason) =>{ if(this.PromiseState !== 'pending') return this.PromiseState = 'rejected' this.PromiseResult = reason // 判断是否有then执行回调 while(this.onRejectedSync.length){ this.onRejectedSync.shift()(this.PromiseResult) } } // then 方法回调 then = (onFulfilled,onRejected)=>{ // 首先确保传进来的是函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason} // 创建一个then返回的Promise const thenPromise = new MyPromise((resolve,reject)=>{ // 创建 then 回调函数的执行函数 const resultPromise = cb =>{ setTimeout(()=>{ // 执行then回调函数,并用try,catch隐式捕捉错误 try { // 调用cb(onFulfilled) // cb(onRejected) const result = cb(this.PromiseResult) //确保不是自身调用 if(result === thenPromise) throw new Error('不能调用自身') // 如果返回的结果还是promise if(result instanceof MyPromise){ // 要判断它的状态,到底是resolve 还是 reject 只有调用它自身的then方法才得知 // 将要返回的resolve,reject,作为它then的回调,这样就能保持一致的状态 result.then(resolve,reject) } // 如果不是返回的promise else{ resolve(result) } } catch (err) { // 抛出的错误,在此捕获并reject掉 reject(err.message) } }) } // 开始执行then回调 if(this.PromiseState === 'fulfilled'){ resultPromise(onFulfilled) } else if(this.PromiseState === 'rejected'){ resultPromise(onRejected) } else if(this.PromiseState === 'pending'){ this.onFulfilledSync.push(onFulfilled) this.onRejectedSync.push(onRejected) } }) // 调用then后返回处理果的结果 return thenPromise } }
测试代码:
let p1 = new MyPromise((resolve,reject)=>{ resolve(2)}) .then(res=> res * 2) .then(res=>{console.log(res)}) // 4 let p2 = new MyPromise((resolve,reject)=>{ resolve(2)}) .then(res=> {throw Error('失败')}) .then(res=>{},err=>{console.log(err);}) // 失败 // 链式加延迟调用 let p3 = new MyPromise((resolve,reject)=>{ resolve(2)}) .then(res=>{ return new MyPromise((resolve,reject)=>{ setTimeout(()=>{resolve(res*2)},1000) }) }) .then(res=>{console.log(res);},err=>{console.log(err);}) // 4
如果你真的搞懂,那么这些你看着也不会有什么问题
最后感谢参考的三心大哥的文章:https://juejin.cn/post/6994594642280857630#heading-15
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。