第一步 基础实现
Promise 代码示例
let p = new Promise((resolve, reject) => {
resolve('success') // reject('fail')
})
p.then((value) => {
console.log(value)
}, (error) => {
console.log(error)
})
代码分析
- Promise是一个类,并在实例化的时候传入了一个立即执行的执行器
- 执行器有两个参数,分别是resolve方法和reject方法,用来修改promise的状态,promise有三个状态,分别是 Pending,Fulfilled,Rejected
- promise的状态确定后(成功或失败)不能更改,需要先对promise的当前状态进行判断,在进行状态更改,缓存返回值
- then方法中,传入两个参数,即成功回调和失败回调,并对当前promise状态判断后调用
代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
constructor(func) {
func(this.resolve, this.reject)
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
}
then(successfulCb, failedCb) {
if (this.status === FULFILLED) {
successfulCb(this.value)
} else if (this.status === REJECTED) {
failedCb(this.reason)
}
}
}
第二步 异步实现
代码示例
let p = new MyPromise((resolve, reject)=> {
setTimeout(() => {
resolve('resolve')
})
})
p.then((value) => {console.log(value)}, (reason) => {console.log(reason)})
代码分析
- 当执行器中包含异步方法时,then方法中不能立即拿到promise的状态,则需要对pending状态进行处理
- then方法执行过程中,当promise状态是pending时,要将成功回调和失败回调进行缓存
- 在异步函数结束,调用resolve或者reject的时候,再执行成功或者失败回调
代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
successfulCallback = null //**改动
failedCallback = null //**改动
constructor(func) {
func(this.resolve, this.reject)
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
this.successfulCallback(this.value) //**改动
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
this.failedCallback(this.reason) //**改动
}
then(successfulCb, failedCb) {
if (this.status === FULFILLED) {
successfulCb(this.value)
} else if (this.status === REJECTED) {
failedCb(this.reason)
} else { //**改动
this.successfulCallback = successfulCb //**改动
this.failedCallback = failedCb //**改动
}
}
}
实现then的链式调用
实例代码
let p = new MyPromise((resolve, reject)=> {
setTimeout(() => {
resolve('resolve')
}, 2000)
})
p.then((value) => {
console.log(value)
return '链式调用1'
}, (reason) => {
console.log(reason)
}).then((value) => {
console.log(value)
return '链式调用2'
}, (reason) => {
console.log(reason)
})
代码分析
- then 返回一个新的promise
- 下一个then方法就是在为上一个then方法返回的promise注册回调,前面的then方法中回调的返回值,会作为后面then方法中回调的参数。
- 如果回调中返回的是promise,那后面then方法的回调会等待他的结果
- then的newpromise中,当状态是成功时,需要判断回调函数的结果,如果是promise则返回promise的状态,否则直接resolve,失败状态同理
- 因为是链式调用,会传入多个成功和失败回调,所以,pending状态应该用数组来存储回调函数,生成成功和失败的回调函数队列
- 在resolve和reject函数中,循环判断当前回调数组的长度是否大于0,对队列顶端函数调用并从队列中移除
- 为了解决异步的情况,pending状态需要想列表中传入一个方法,并在方法中对回调函数进行调用,判断,如成功和失败的状态判断过程。
代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
successfulCallback = []
failedCallback = []
constructor(func) {
func(this.resolve, this.reject)
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while(this.successfulCallback.length) this.successfulCallback.shift()()
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while(this.failedCallback.length) this.failedCallback.shift()()
}
then(successfulCb, failedCb) {
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let result = successfulCb(this.value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} else if (this.status === REJECTED) {
let result = failedCb(this.reason)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} else {
this.successfulCallback.push(() => {
let result = successfulCb(this.value)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
this.failedCallback.push(() => {
let result = failedCb(this.reason)
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
}
})
return newPromise
}
}
异常处理1-promise的then不能返回自身的promise
示例代码
let p = new Promise((resolve, reject)=> {
resolve('success')
})
let p1 = p.then((value) => {
console.log(value)
return p1
}, (error) => {
console.log(error)
})
p1.then((value) => {
console.log(value)
}, (error) => {
console.log(error) //输出error[TypeError: Chaining cycle detected for promise #<Promise>]
})
代码分析
- 由于then返回一个promise,如果then内部的回调也返回的是同一个promise的话,相当于这个promise要等待自己完成,这是不被允许的,所以会报类型错误:Chaining cycle detected for promise
- 在then方法获取成功或失败的结果后,需要判断这个结果是不是then所返回的promise,要获取newpromise就需要把比较过程放在定时器里面,因为定时器会开启一个宏任务,能够拿到newpromise
- 在这里,也可以把这部分代码抽离出去,然后进行比较以及后续处理。
代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
successfulCallback = []
failedCallback = []
constructor(func) {
func(this.resolve, this.reject)
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while(this.successfulCallback.length) this.successfulCallback.shift()()
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while(this.failedCallback.length) this.failedCallback.shift()()
}
then(successfulCb, failedCb) {
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
})
} else if (this.status === REJECTED) {
setTimeout(() => {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
})
} else {
this.successfulCallback.push(() => {
setTimeout(() => {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
})
})
this.failedCallback.push(() => {
setTimeout(() => {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
})
})
}
})
return newPromise
}
}
function resolvePromise(newPromise, result, resolve, reject) {
if (newPromise === result) {
return reject('TypeError: Chaining cycle detected for promise #<Promise>')
}
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
}
异常处理2-promise执行过程中的错误处理
示例代码
let p = new Promise((resolve, reject)=> {
resolve('success')
})
p.then((value) => {
console.log(value)
throw 'new error' //在then中抛出错误
}, (error) => {
console.log(error)
}).then(() => {}, (error) => {
console.log(error) //接收error
})
代码分析
- 要捕获then中方法执行过程中抛出的错误,可以使用trycatch来对代码块进行包装,拿到错误并reject。
- 执行器阶段也同样需要做try catch处理,去捕获执行器阶段的错误。
实现代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
successfulCallback = []
failedCallback = []
constructor(func) {
try { //执行器执行错误捕获处理
func(this.resolve, this.reject)
} catch(e) {
this.reject(e)
}
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while(this.successfulCallback.length) this.successfulCallback.shift()()
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while(this.failedCallback.length) this.failedCallback.shift()()
}
then(successfulCb, failedCb) {
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try { //成功回调函数错误捕获
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch(e) {
reject(e)
}
})
} else if (this.status === REJECTED) {
setTimeout(() => {
try { //失败回调函数错误捕获
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch(e) {
reject(e)
}
})
} else {
this.successfulCallback.push(() => {
setTimeout(() => {
try { //pending阶段缓存成功回调函数错误捕获
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.failedCallback.push(() => {
setTimeout(() => {
try { //pending阶段缓存失败回调函数错误捕获
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return newPromise
}
}
function resolvePromise(newPromise, result, resolve, reject) {
if (newPromise === result) {
return reject('TypeError: Chaining cycle detected for promise #<Promise>')
}
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
}
promise-then函数参数处理
示例代码
let p = new Promise((resolve, reject)=> {
resolve('success')
})
p.then(1).then(2).then((value) => {
console.log(value)
})
代码分析
- then中接受2个参数,分别是成功回调和失败回调
- then方法内,需要判断回调函数是否存在,如果不存在,则将promise结果透传到下一个then函数中,以此类推。
- 在实现的时候,需要判断回调函数是否存在,如果不存在,则将当前结果赋值给参数,让then函数生成包裹着当前结果的promise,以便后续的then方法接收
代码实现
//then方法
then (successfulCb, failedCb) {
successfulCb = successfulCb ? successfulCb : value => value //判断成功回调
failedCb = failedCb ? failedCb : reason => {throw reason} //判断失败回调
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
this.successfulCallback.push(() => {
setTimeout(() => {
try {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.failedCallback.push(() => {
setTimeout(() => {
try {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return newPromise
}
catch方法
示例代码
let p = new Promise((resolve, reject)=> {
reject('error')
})
p.then((value) => {
console.log(value)
// throw 'error2'
}).catch((error) => {
console.log(error)
})
代码分析
- catch用来捕获promise中的错误,可以是执行器中reject的错误,也可以是then中的回调函数中抛出的错误。
- catch的返回结果也是一个promise, 他只有一个失败的回调。
- 所以catch的实现过程就是调用当前promise的then方法,传入失败的回调函数,并返回这个then的执行结果。
代码实现
catch(failedCb) {
return this.then(void 0, failedCb)
}
all方法实现
代码示例
let p1 = new Promise((resolve, reject) => {
resolve(1)
})
let p2 = new Promise((resolve, reject) => {
resolve(2)
})
Promise.all([p1, p2]).then((result) => {
console.log(result)
})
代码分析
- all方法的功能是数组中所有promise都成功时的返回结果
- all方法直接在Promise上调用,它是Promise上的一个静态方法
- all有一个参数,是一个数组,该数组可以是promise,也可以是普通值
- all返回一个promise,该promise的成功返回值是参数列表中promise成功结果或普通值组成的数组,失败结果会接受参数列表中第一个失败的返回值
代码实现
static all(arr) {
let resultArray = []
let count = 0
return new MyPromise((resolve, reject) => {
function addItem(value) {
resultArray.push(value)
count++
if (count === arr.length) {
resolve(resultArray)
}
}
arr.forEach((item) => {
if (item instanceof MyPromise) {
item.then((value) => {
addItem(value)
}, (reason) =>{
reject(reason)
})
} else {
addItem(item)
}
})
})
}
resolve 实现
示例代码
Promise.resolve(1).then((value) => console.log(value))
代码分析
- resolve返回一个成功状态的promise
- resolve在Promise类上直接调用,所以他是一个静态方法
- resolve 接受一个参数,这个参数可能是普通值,也可能是一个promise
- 当参数是promsie,则直接返回;如果参数是普通值,则将参数包装成promise再返回
代码实现
static resolve(value) {
if (value instanceof MyPromise) {
return value
} else {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
}
finally 实现
示例代码
let p = new Promise((resolve, reject) => {
resolve(1)
})
p.then((value) => {
console.log(value)
throw 2
}).catch((error) => {
console.log(error)
}).finally(() => {
console.log('finally')
})
代码分析
- finally一般then和catch的后面,不论当前promise的结果是什么,finally都被被执行
- finally的参数是一个回调函数
- finally后面可以继续跟then或catch 进行链式调用,所以finally方法的返回值也是一个promise
- 实现过程是在当前promise的then的回调中分别将参数中的回调的执行结果包装成promise,然后再then中进行当前promise的值透传
代码实现
finally(callback) {
return this.then(() => {
return MyPromise.resolve(callback()).then((value) => value)
}, () => {
return MyPromise.resolve(callback()).then((reason) => {throw reason})
})
}
完整代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING
value = null
reason = null
successfulCallback = []
failedCallback = []
constructor(func) {
try {
func(this.resolve, this.reject)
} catch(e) {
this.reject(e)
}
}
resolve = (value) => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while(this.successfulCallback.length) this.successfulCallback.shift()()
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while(this.failedCallback.length) this.failedCallback.shift()()
}
then(successfulCb, failedCb) {
successfulCb = successfulCb ? successfulCb : value => value
failedCb = failedCb ? failedCb : reason => { throw reason }
let newPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch(e) {
reject(e)
}
})
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch(e) {
reject(e)
}
})
} else {
this.successfulCallback.push(() => {
setTimeout(() => {
try {
let result = successfulCb(this.value)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.failedCallback.push(() => {
setTimeout(() => {
try {
let result = failedCb(this.reason)
resolvePromise(newPromise, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return newPromise
}
catch (failedCb) {
return this.then(void 0, failedCb)
}
finally(callback) {
return this.then(() => {
return MyPromise.resolve(callback()).then((value) => value)
}, () => {
return MyPromise.resolve(callback()).then((reason) => {throw reason})
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
} else {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
}
static all(arr) {
let resultArray = []
let count = 0
return new MyPromise((resolve, reject) => {
function addItem(value) {
resultArray.push(value)
count++
if (count === arr.length) {
resolve(resultArray)
}
}
arr.forEach((item) => {
if (item instanceof MyPromise) {
item.then((value) => {
addItem(value)
}, (reason) =>{
reject(reason)
})
} else {
addItem(item)
}
})
})
}
}
function resolvePromise(newPromise, result, resolve, reject) {
if (newPromise === result) {
return reject('TypeError: Chaining cycle detected for promise #<Promise>')
}
if (result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
}
————————————————个人杂记————————————————————