promise.js
/**
* 第一步:
* 1. promise 接受一个执行器参数,该执行器以一个两个参数resolve, reject
* 执行器是创建对象立即执行的, 所以执行器实在构造函数里
*
* 2. 状态:三种分别是, 状态字符串, 可以定义成常量, 在
* pedding: 等待中
* fulfilled: 成功
* rejected: 失败
* 状态可以从:pedding --> fulfilled, 或者 pedding --> rejected,
* 状态一旦确定, 就不可在改变
* 3. 执行器里面的resolve, reject 方法执行时, 就会改变对应的状态的, 状态是需要保存的, 定义保存status
* resolve: pedding --> fulfilled, 该方法是处理成功的,
* 接受一个成功数据参数value(异步操作的结果), value是在then 方法的第一个参数(函数参数)里使用的
* reject: pedding -->rejected 该方法是处理失败的
* 接受一个失败数据参数reason(异步操作失败的原因), reason,是在then 方法的第二个参数(函数参数)里使用的
*
* 4. then: 该方法内部判断状态, 如果是成功状态, 就执行成功回调函数(successCallBack), 如果失败就调用失败回调函数(failCallBack), 该方法是prosie对象调用, 所以直接定义在原型对象(MyPromisele类)中
* successCallBack: 接受一个参数:操作成功之后的值, 分同步,异步操作两种情况
* failCallBack: 接受一个参数, 操作失败的原因, 分同步,异步操作两种情况
* 可以被调用多次, 也就是successCallBack, failCallBack的存储是一个数组
* then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值,
* 回调函数返回值, 不能自己返回自己
*
* 第二步:all : 并行执行
* catch
* resolve
* catch
* finally
*/
const PEDDING = 'pedding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Mypromsie {
constructor (excutor) {
excutor(this.resolve, this.reject) // 接受两个参数分别是 resolve, reject, 在Mypromsie类定义这两个属性
}
status = PEDDING // 默认值
_value = undefined // 保存成功的值
_reason = undefined // 保存失败的原因
successCallBack = [] // then 里注册的成功回调函数
failCallBack = [] // then 里注册的失败回调函数
resolve = value => { // then 回调函数中会使用value 所以保存起来
if (!Object.is(this.status, PEDDING)) return // 状态一旦确定就不可在变化
this.status = FULFILLED
this._value = value
while(this.successCallBack.length) { // 如果存在, 则是异步操作
// this.successCallBack(this._value)
this.successCallBack.shift()() // 传递的函数里含有this.value所以这里不需要了
}
}
reject = reason => { // then 回调函数中会使用reason 所以保存起来
if (!Object.is(this.status, PEDDING)) return // 状态一旦确定就不可在变化
this.status = REJECTED
this._reason = reason
while(this.failCallBack.length) { // 如果存在, 则是异步操作
this.failCallBack.shift()()
}
}
then(successCallBack, failCallBack) { // 分同步操作, 和异步操作分别处理
const promise2 = new Promise((resolve, reject) => { // successCallBack,failCallBack的返回值,promsie2的resolve, reject方法的的参数值一直传递下去
if (Object.is(this.status, FULFILLED)) {
// 这里 promise2 还没有初始化, 所以这里拿不到, 所以这里 使用异步,让其先初始化
setTimeout(() => {
try {
const x = successCallBack(this._value) // 异步操作成功的值, 传给成功回调, 同步操作情况下, 同步情况下, 回调函数直接执行, 不需要存储到数组
resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
} catch (e) { // 捕获异常, 执行reject
reject(e)
}
}, 0)
} else if (Object.is(this.status, REJECTED)) {
setTimeout(() => {
try {
const x = failCallBack(this._reason) // 异步操作失败的值, 传给失败回调, 同步操作情况下,同步情况下, 回调函数直接执行, 不需要存储到数组
resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
} catch (e) { // 捕获异常, 执行reject
reject(e)
}
}, 0)
if (successCallBack) {
this.successCallBack.push(() => {
setTimeout(() => {
try {
const x = successCallBack(this._value)
resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
} catch (e) { // 捕获异常, 执行reject
reject(e)
}
}, 0)
}) // 这里不能像上面的successCallBack那样直接获取返回值(因为状态还没有该拜年), 利用高阶函数,返回一个函数,就行
}
if (failCallBack) {
this.failCallBack.push(() => {
setTimeout(() => {
try {
const x = failCallBack(this._reason)
resolvePromise(promise2, x, resolve, reject) // successCallBack的回调函数的返回值, 被传递到resolve方法中
} catch (e) { // 捕获异常, 执行reject
reject(e)
}
}, 0)
})
}
}
})
return promise2 // 返回promise以实现then 的链式调用
}
// 捕获整个promise链的异常
catch(failCallBack) {
return this.then(undefined, failCallBack)
}
/**
* @param {*} callback
* @memberof Mypromsie
* 不管是成功,还是失败都会执行这个方法
*/
finally(callback) {
return this.then(value => {
return new Mypromsie.resolve(callback()).then(() => value)
}, reason => {
return new Promise.resolve(callback()).then(() => {
throw reason
})
})
}
/**
* @static
* @param {*} array promise 数组
* @memberof Mypromsie
* @return 返回的也是一个promise
* 数组的promise必须全部完成, 这个promise才完成
*/
static all(array) {
let result = [] // promise 的执行结果
let index = 0 // 第几个promsie
return new Mypromsie((resolve, reject) => {
// 把promise的处理结果, 添加进数组
function addData(_index, data) {
result[_index, data] // promise 的执行期可能不是同步的, 所以不能使用Push
++index
if (result.length === index) { // 数组的长度和inde长度一致吗, 说明所有promise 都执行完成了
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof Mypromsie) {
// Mypromise 对象
current.then(value => {
addData(i, value) // 添加
}, reason => {
reject(reason) // 整个promise 结束
})
} else { // 普通值, 直接添加
addData(i, current)
}
}
})
}
/**
* @static
* @param {*} value
* @returns
* @memberof Mypromsie
* 如果是promise 就直接返回
* 如果是普通对象, 则包裹成promsie
*/
static resolve(value) {
if (value instanceof Mypromsie) return value
return new Mypromsie(resolve => resolve(value))
}
}
/**
*
*
* @param {*} 调用的promise
* @param {*} 返回的值
* @param {*} resolve
* @param {*} reject
* @return
* @memberof Mypromsie
* 如果是普通值 直接调用resolve
* 如果是promise对象 查看promsie对象返回的结果
* 再根据promise对象返回的结果 决定调用resolve 还是调用reject
*/
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) { // 防止自己返回自己, 造成死循环
return reject(new Error('Chaining cycle detected for promise #<Promise>'))
}
//then 返回的是 promise 对象
// 则 返回x.then(valuie => resolve(x), reason => reject(reason))
if (x instanceof Mypromsie) {
x.then(resolve, reject) // 简写
} else {
resolve(x) // 普通值
}
}
module.exports = Mypromsie // 导出
测试文件test.js
/**
* 测试
*/
const MyPromise = require('./myPromise')
const promise = new MyPromise((resolve, reject) => {
// resolve('测试成功') // 测试成功
// reject(new Error('测试失败 error')) // 测试失败
// reject(new Error('测试状态不可以在改变 error')) // 测试状态不可以在改变
// setTimeout(() => {
// // resolve('测试异步成功')
// reject(new Error('测试异步失败'))
// }, 1000)
reject(new Error('catch'))
})
// promise.then(res => {
// // console.log('res', res)
// setTimeout(() => {
// console.log('then1', res)
// }, 1000)
// return '测试then的链式调用'
// }, reason => {
// console.log('reason', reason.message)
// })
// .then(res => {
// console.log(res)
// })
// promise.then(res => { // 测试连续调用h then
// setTimeout(() => {
// console.log('then', res)
// }, 2000)
// }, reason => {
// console.log('reason', reason.message)
// })
const promise2 = promise.then(value => {
console.log('promise2', value)
}, reason => {
console.log('reject', reason)
})
promise.catch(reason => { // 测试catch
console.log('catch', reason)
}).finally(() => {
console.log('finally')
})