「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。
传送门
从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现 从零手撕Promise,掌握Promise的实现原理(6)之then方法的回调为什么是异步微任务
回顾
经过前几次的介绍我们的Promise,现在长这样
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
}
class Promise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = undefined
//存放onFulfilled
this.onResolvedCallbacks = []
//存放onRejected
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === PENDING) {
this.value = value
this.state = FULFILLED
//promise实例状态改变后调用暂存的onFulfilled
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
//promise实例状态改变后调用的onRejected
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
//executor函数执行过程中出错,将会导致Promise失败
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected){
let promise = new Promise((resolve, reject) => {
switch(this.state){
case FULFILLED:
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
case REJECTED:
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
default:
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
}
})
return promise
}
}
then方法的链式调用之resolvePromise方法
-
resolvePromise的作用,主要是为了解析then的回调函数的返回值,从而来确定,本次then方法应该返回什么状态的Promise。 -
- 首先判断
x是基础类型数据,还是引用类型,基础类型的数据直接resolve,即可。
- 首先判断
-
- 如果是引用类型的数据,尝试获取
x上的then属性(x.then),如果在获取属性的时候报异常则reject
- 如果是引用类型的数据,尝试获取
-
- 判断
then是否是函数,如果是一个函数则我们认定它为Promise,如果不是则resolve
- 判断
-
- 如果
x是一个Promise,我们则调用他的then方法,然后在then方法的回调中,去调用resolve或者reject,假如调用时报错则reject
- 如果
-
- 由此可见假如then函数中的回调返回了
Promise,那么then函数的返回值的状态与回调返回的Promise状态息息相关。
- 由此可见假如then函数中的回调返回了
/*
promise => then函数要返回的promise
x => then函数中回调函数的返回值
resolve => then函数要返回的promise的resolve
reject => then函数要返回的promise的reject
*/
const resolvePromise = (promise, x, resolve, reject) => {
// 1.
if(x !== null && /^(object|function)$/.test(typeof x)){
let then
// 2. 如果是引用类型的数据,尝试获取`x`上的`then`属性(`x.then`),如果在获取属性的时候报异常则`reject`
try{
then = x.then
}catch(e){
reject(e)
}
//3. 判断`then`是否是函数,如果是一个函数则我们认定它为`Promise`,如果不是则`resolve`
if(typeof then === 'function'){
// 4. 如果`x`是一个`Promise`,我们则调用他的`then`方法,然后在`then`方法的回调中,去调用`resolve`或者`reject`,假如调用时报错则`reject`
try{
then.call(x, (y) => {
resolvePromise(promise, y, resolve, reject)
},(r) => {
reject(r)
})
}catch(e){
reject(e)
}
}else{
resolve(x)
}
}else{
//基础类型数据直接resolve
resolve(x)
}
}
- 6.对于下面图片中序号1处再次递归调用
resolvePromise的作用是为了防止,例如下面这段代码,返回的结果是一个多次嵌套的Promise,依次需要去递归解析。
let p = new Promise((resolve,reject) => {
resolve('成功')
})
p.then(value => {
console.log('value',value);
//此处then成功的回调函数中返回的是一个Promise,它的值又是一个Promise,多次Promise嵌套.
//所以递归调用resolvePromise就是为了解决这种情况
return new Promise((resolve,reject) => { //第一个promise
resolve(
//第二个promise
new Promise((resolve,reject) => {
resolve('成功')
})
)
})
},reason => {
console.log('reason',reason);
}).then(value => {
console.log('value',value);
},reason => {
console.log('reason',reason);
})
- 执行结果
打印两次结果,正确。(第一次为
p.then打印,第二次为p.then.then打印)
到这里我们的Promise长这样了
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const resolvePromise = (promise, x, resolve, reject) => {
// 1. 首先判断`x`是基础类型数据,还是引用类型,基础类型的数据直接`resolve`,即可。
if(x !== null && /^(object|function)$/.test(typeof x)){
let then
// 2. 如果是引用类型的数据,尝试获取`x`上的`then`属性(`x.then`),如果在获取属性的时候报异常则`reject`
try{
then = x.then
}catch(e){
reject(e)
}
//3. 判断`then`是否是函数,如果是一个函数则我们认定它为`Promise`,如果不是则`resolve`
if(typeof then === 'function'){
//4. 如果`x`是一个`Promise`,我们则调用他的`then`方法,然后在`then`方法的回调中,去调用`resolve`或者`reject`,假如调用时报错则`reject`
try{
then.call(x, (y) => {
resolvePromise(promise, y, resolve, reject)
},(r) => {
reject(r)
})
}catch(e){
reject(e)
}
}else{
resolve(x)
}
}else{
//基础类型数据直接resolve
resolve(x)
}
}
class Promise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = undefined
//存放onFulfilled
this.onResolvedCallbacks = []
//存放onRejected
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === PENDING) {
this.value = value
this.state = FULFILLED
//promise实例状态改变后调用暂存的onFulfilled
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
//promise实例状态改变后调用的onRejected
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
//executor函数执行过程中出错,将会导致Promise失败
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected){
let promise = new Promise((resolve, reject) => {
switch(this.state){
case FULFILLED:
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
case REJECTED:
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
break
default:
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFulfilled(this.value)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(promise, x, resolve, reject)
} catch(e){
reject(e)
}
})
})
}
})
return promise
}
}
module.exports=Promise
到这一步,我们的then方法,还有些小瑕疵,马上我们的Promise就要大功告成了,下篇文章将继续完成
传送门
从零手撕Promise,掌握Promise的实现原理(1)之promise基本结构的实现 从零手撕Promise,掌握Promise的实现原理(2)之基础版本的promise实现 从零手撕Promise,掌握Promise的实现原理(3)之回调地狱是什么 从零手撕Promise,掌握Promise的实现原理(4)之then方法链式调用的初步实现 从零手撕Promise,掌握Promise的实现原理(5)之then方法链式调用的进阶实现 从零手撕Promise,掌握Promise的实现原理(6)之then方法的回调为什么是异步微任务