已通过Promise A+规范测试,仅用于学习,加深理解Promise
console.log("================promise================")
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECT = 'rejected'
/**
* 异步任务-函数封装
* 1、定义函数
* 2、调用核心异步方法,(queueMicrotask, MutationObserver, setTimeout)
*
* @param {*} callback 回调函数
*/
function runAsynctask(callback) {
// 2、调用核心异步方法,(queueMicrotask, MutationObserver, setTimeout)
// 兼容性判断
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = 'Promise 666'
} else {
// 使用setTimeout 兜底
setTimeout(callback, 0)
}
}
class MyPromise {
PromiseState = PENDING
PromiseResult = void 0
onFulfilledCallBack = []
onRejectedCallBack = []
constructor(executor) {
const resolve = (data) => {
if (this.PromiseState !== PENDING) return
this.PromiseState = FULFILLED
this.PromiseResult = data
// 调用成功的回调
this.onFulfilledCallBack.forEach(onFulfilled => {
onFulfilled(data)
})
}
const reject = (reason) => {
if (this.PromiseState !== PENDING) return
this.PromiseState = REJECT
this.PromiseResult = reason
// 调用失败的回调
this.onRejectedCallBack.forEach(onRejected => {
onRejected(reason)
})
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// promise 规范 解决过程
// 1、如果x不是对象或函数,则直接用x作为值来实现Promise。
then(onFulFilled, onRejected) {
// 1、如果x不是对象或函数,则直接用x作为值来实现Promise。
onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 链式调用返回一个promise
const p2 = new MyPromise((resolve, reject) => {
// 如果成功执行成功 ,如果失败执行失败
if (this.PromiseState === FULFILLED) {
// 使用封装的异步方法包裹
runAsynctask(() => {
try {
// 获取到返回值 调用resolve方法 触发链式调用的then方法的第一个回调
const res = onFulFilled(this.PromiseResult)
// 4、调用函数
resolvePromise(p2, res, resolve, reject)
// 1、处理重复引用
// if (res === p2) {
// throw new TypeError('Chaining cycle detected for promise #<Promise>')
// }
// if (res instanceof MyPromise) {
// res.then(res => resolve(res), error => reject(error))
// } else {
// resolve(res)
// }
} catch (error) {
reject(error)
}
})
} else if (this.PromiseState === REJECT) {
// 使用封装的异步方法包裹
runAsynctask(() => {
try {
// 2、获取到返回值 调用resolve方法 触发链式调用的then方法的第二个回调
const res = onRejected(this.PromiseResult)
// 4、调用函数
resolvePromise(p2, res, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.PromiseState === PENDING) {
// 如果都不是说明是一个异步操作
// 使用封装的异步方法包裹
this.onFulfilledCallBack.push(() => {
runAsynctask(() => {
// 1、处理异常
try {
const res = onFulFilled(this.PromiseResult)
resolvePromise(p2, res, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallBack.push(() => {
runAsynctask(() => {
// 1、处理异常
try {
const res = onRejected(this.PromiseResult)
resolvePromise(p2, res, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
// 传入如果是promise 就直接返回,如果不是就返回成功的promise
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(value) {
return new MyPromise((undefined, reject) => {
reject(value)
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
// 判断传入的是不是数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3、等待第一个promise 敲定
promises.forEach(p => {
MyPromise.resolve(p).then(res => {
resolve(res)
}, error => {
reject(error)
})
})
})
}
/**
* 静态方法-all
* 1、返回promise实例
* 2、判断是否为数组 错误信息: Argument is not iterable
* 3、如果是空数组直接兑现
* 4、如果全部成功就全部兑现 返回数组
* 4.1、记录结果 使用索引来记录 保证顺序性
* 4.2、判断全部兑现
* 5、如果有拒绝处理第一个拒绝
* @param {*} promises
* @returns
*/
static all(promises) {
return new MyPromise((resolve, reject) => {
// 2、判断是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3、空数组直接兑现
promises.length === 0 && resolve(promises)
// 4、如果全部成功就全部兑现 返回数组
let count = 0
let result = []
promises.forEach((p, index) => {
MyPromise.resolve(p).then(res => {
result[index] = res
count++
// 4.2、全部兑现
count === promises.length && resolve(result)
}, err => {
// 5、处理第一个拒绝
reject(err)
})
});
})
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 2、判断是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3、空数组直接兑现
promises.length === 0 && resolve(promises)
let count = 0
let result = []
promises.forEach((p, index) => {
MyPromise.resolve(p).then(res => {
result[index] = { status: FULFILLED, value: res }
count++
count === promises.length && resolve(result)
}, err => {
result[index] = { status: REJECT, reason: err }
count++
count === promises.length && resolve(result)
})
})
})
}
/**
* 等待第一个成功或者全部都拒绝,全部都拒绝返回一个报错,进catch
* @param {*} promises
*/
static any(promises) {
return new MyPromise((resolve, reject) => {
// 2、判断是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
// 3、空数组直接兑现
promises.length === 0 && reject(new AggregateError(promises, 'All promise were rejected'))
let count = 0
let errors = []
// 4、第一个兑现
promises.forEach((p, index) => {
MyPromise.resolve(p).then(res => {
resolve(res)
}, err => {
errors[index] = err
count++
count === promises.length && reject(new AggregateError(errors, 'All promise were rejected'))
})
})
})
}
}
// 1、 抽取函数
// function resolvePromise(p2, res, resolve, reject) {
// // 1、处理重复引用
// if (res === p2) {
// throw new TypeError('Chaining cycle detected for promise #<Promise>')
// }
// if (res instanceof MyPromise) {
// res.then(res => resolve(res), error => reject(error))
// } else {
// resolve(res)
// }
// }
// 符合promise / A+ 规范(考虑了各种情况)
function resolvePromise(p2, x, resolve, reject) {
// 2.3.3.1 如果p2和x引用同一个对象,通过typeError作为原因来拒绝promisse
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise')
}
/**
* 2.3.3.2 如果x是一个promise,采用他的状态
* 2.3.3.3.1 如果x是pending状态,promise必须保持等待状态,直到x被fulfilled或rejected
* 2.3.3.3.2 如果x是fuifilled状态,用相同的原因解决promise
* 2.3.3.3.3 如果x是rejected状态,用相同的原因拒绝promise
*/
if (x instanceof MyPromise) {
x.then(y => {
resolvePromise(p2, y, resolve, reject)
}, reject)
}
// 2.3.3 如果x 是一个对象或者函数
else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 2.3.3.1 让then成为x.then
try {
var then = x.then;
} catch (e) {
// 2.3.3.2 如果检索属性x.then 抛出了异常e,用e作为原因拒绝promise
return reject(e)
}
/**
* 2.3.3.3 如果then是一个函数,通过call调用他,并且将x作为他的this(参数1)
* 调用then时传入两个回调函数:
* 第一个参数叫做resolvePromsie(对应到参数2)
* 第二个参数叫做rejectPromise(对应到参数3)
*/
if (typeof then === 'function') {
// 2.3.3.3.3 如果resolvePromise 和rejectPromise 均被调用,
// 或者同一参数被调用了多次,
// 只采用第一次调用,后续的调用会被忽略
let called = false
try {
then.call(
x,
// 2.3.3.3.1 如果resolvePromise 以 成功原因 y 作为参数被调用,继续执行resolvePromise
y => {
if (called) return
called = true
resolvePromise(p2, y, resolve, reject)
},
// 2.3.3.3.2 如果rejectPromise 以拒绝原因 r 为参数被调用,继续执行resolvePromise
r => {
if (called) return
called = true
reject(r)
})
}
catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
} else {
return resolve(x)
}
}
let aaa = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(124124)
}, 1000);
})
let bbb = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(12412412)
}, 500);
})
let ccc = MyPromise.reject(2)
const p = MyPromise.any([aaa, bbb, ccc])
p.then(res => {
console.log('then', res)
}).catch(error => {
console.dir(error)
})
module.exports = {
deferred() {
const res = {}
res.promise = new MyPromise((resolve, reject) => {
res.resolve = resolve
res.reject = reject
})
return res
}
}