-
promise存在三种状态:成功(resolved),失败(rejected),进行中(pending)
-
promise的状态一旦改变就不能再改,状态只能从进行中(pending)改变到别的状态
-
promise是一个构造函数,接受一个构造器,构造器立刻执行两个函数,resolve是成功函数,返回一个成功值,reject是失败函数,返回失败原因
先实现一个普通的promise构造函数
// 先实现一个小型的promise
class Promse {
// 接收一个执行器 两个函数 并且立马执行
constructor(executor) {
// 先定义初始状态 初始成功值 初始失败原因
status = 'pending'
value = undefined
reason = undefined
executor(this.resolve, this.reject)
// 两个函数
// 成功返回成功的值
resolve = (value) => {
if (this.status !== 'pending') return
this.status = 'resolved'
this.value = value
}
// 失败返回失败原因
reject = (reason) => {
if (this.status !== 'pending') return
this.status = 'rejected'
this.reason = reason
}
}
}
定义两个函数用于改变promise的状态,只能是从pending状态改变,其他状态直接返回
实现then方法
then方法中接受两个函数,成功和失败,当promise是pending状态下,对应执行函数
// then方法 接受两个参数
then (onFulfilled, onRejectedFunc) {
if (this.status === 'pending') {
// 然后对应状态分别函数
if (this.status === 'resolved') {
onFulfilled(this.value)
}
if (this.status === 'resolved') {
onRejectedFunc(this.reason)
}
}
}
这样子,我们初版的promise是已经完成了,但是这里缺少了一个关键的点,函数里面如果出现是异步操作就会失败,因为这样子只是在状态改变之后执行函数,如果存在异步,那状态改变之前就不会执行
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(100)
}, 100)
})
p1.then(value => {
console.log(value)
})
如果是这样子的情况,promise的状态还没有改变,就先执行then的函数,就会导致then中的方法没被执行,为了解决异步执行,我们在promise类中新增两个值
// 先实现一个小型的promise
class Promse {
// 接收一个执行器 两个函数 并且立马执行
constructor(executor) {
// 先定义初始状态 初始成功值 初始失败原因
status = 'pending'
value = undefined
reason = undefined
// 初始化两个数组 用于存放成功的回调函数和失败的回调函数
onFulfilled = []
onRejectedFunc = []
executor(this.resolve, this.reject)
}
新增了两个数组,onFulfilled和onRejectedFunc用于存放成功的回调函数和失败的回调函数,先把需要执行的函数都存放在执行栈中,当状态改变的那一瞬间才去执行函数,这样子就可以解决异步了
// then方法 接受两个参数
then (onFulfilled, onRejectedFunc) {
if (this.status === 'pending') {
// 如果当前promise是进行中 并且接受到的参数是函数 则把它们放进对应的执行栈中
// 放进执行栈中 就是为了方便处理异步执行的情况
if (typeof onFulfilled === 'function') {
this.onFulfilled.push(onFulfilled)
}
if (typeof onRejectedFunc === 'function') {
this.onRejectedFunc.push(onRejectedFunc)
}
// 然后对应状态分别函数
if (this.status === 'resolved') {
onFulfilled(this.value)
}
if (this.status === 'resolved') {
onRejectedFunc(this.reason)
}
}
}
现在then方法中添加逻辑,把对应的函数放到对应的执行栈中
resolve = (value) => {
if (this.status !== 'pending') return
this.status = 'resolved'
this.value = value
this.onFulfilled.forEach(fn => fn())
}
// 失败返回失败原因
reject = (reason) => {
if (this.status !== 'pending') return
this.status = 'rejected'
this.reason = reason
this.onRejectedFunc.forEach(fn => fn())
}
在resolve和reject两个函数中去循环调用执行栈的函数,这样子就避免了then先执行,但是状态没被改变的情况
then的链式调用
-
链式调用的前提是上一个then的返回时一个promise
-
如果then内部的回调函数执行依然是一个promise,那就把promise的结果resolve出去
-
任何的promise必须要resolve之后才会到then方法,从而创建下一个promise
-
当then中返回一个普通值或者一个成功的promise,就走成功的回调
-
当then中返回一个失败的promise或者抛出异常,就走失败的回调
这里我们添加一个resolvePromise的方法来解决链式调用的问题
/**
*
* @param {*} promise2 // 链式回调中新的promise
* @param {*} x // 处理的目标的函数,既上一个promise中的处理函数
* @param {*} resolve // 新promise的resolve
* @param {*} reject // 新promise的reject
*/
resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Promise发生了循环调用, 自己调用自己'))
}
// 判断 如果传进来的目标函数是一个对象或者是一个方法 那有可能是promise 就有then
if (x !== null && (typeof x === 'object') || (typeof x === 'fuction')) {
// 先获取then方法 为了避免风险 写在try里面
try {
setTimeout(() => {
let then = x.then
if (typeof then === 'function') {
// 如果有 就执行他的then里方法
then.call(x, y => {
this.resolvePromise(promise2, y, resolve, reject)
}, r => {
reject(r)
})
} else {
resolve(x)
}
}, 0)
} catch (e) {
reject(e)
}
} else {
resolve(x)
}
}
当我们接受到一个promise的时候,执行它的then方法,如果链式调用中返回的不是promise,就不用调用下一个的then
然后我们需要修改then方法里面的处理逻辑
then (onFulfilled, onRejectedFunc) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === 'pending') {
// 如果当前promise是进行中 并且接受到的参数是函数 则把它们放进对应的执行栈中
// 放进执行栈中 就是为了方便处理异步执行的情况
if (typeof onFulfilled === 'function') {
this.onFulfilled.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (typeof onRejectedFunc === 'function') {
this.onRejectedFunc.push(() => {
try {
let x = onRejectedFunc(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// 然后对应状态分别函数
if (this.status === 'resolved') {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}
if (this.status === 'resolved') {
try {
let x = onRejectedFunc(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}
}
})
}
在我们在执行then里面的函数时,先创建一个新的promise为了链式的调用,然后再处理对应逻辑时,把新的promise和当前需要处理的函数作为参数传入到resolvePromise方法中,这样子就可以实现链式的调用
本文使用 mdnice 排版