定义私有属性
const MyPromise = (() => {
// 私有属性用WeakMap定义,放到放到IIFE(立即执行函数)里,形成闭包,做到属性私有
const status = new WeakMap() // 存放Promise三个状态值
const value = new WeakMap() // fulfilled存放的值
const reason = new WeakMap() // rejected存放的值
const callbacks = new WeakMap() // pending时将then方法onFulfilled和onRejected存放到这,等待fulfilled或rejected时执行
return class {
constructor() {
// 私有属性初始化
status.set(this, PENDING)
value.set(this, null)
reason.set(this, null)
callbacks.set(this, [])
}
}
})()
定义 Promise的三个状态,实例方法和静态方法
const MyPromise = (() => {
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
return class {
then() {} // 后边实现
catch() {} // 后边实现
static resolve() {} // 后边实现
static reject() {} // 后边实现
static all() {} // 后边实现
static race() {} // 后边实现
}
})()
添加constuctor里的执行器
class {
constuctor(executor/*执行器*/) {
/* ...私有属性初始化 */
const resolve = () => {} // 后边实现
const reject = () => {} // 后边实现
try {
executor(resolve, reject)
} catch(error) {
reject(error)
}
}
}
实现executor执行器的resolve和reject
const resolve = (val) => {
if(status.get(this) === PENDING) {
status.set(this, FULFILLED)
value.set(this, val)
setTimeout(() => { // 模拟Promise推入任务队列
const cbs = callbacks.get(this)
const len = cbs.length
for(let i = 0; i < len; i++) {
this.callbacks[i].onFulfilled(value)
}
})
}
}
const resolve = (val) => {
if(status.get(this) === PENDING) {
status.set(this, REJECTED)
reason.set(this, val)
setTimeout(() => { // 模拟Promise推入任务队列
const cbs = callbacks.get(this)
const len = cbs.length
for(let i = 0; i < len; i++) {
this.callbacks[i].onRejected(value)
}
})
}
}
这两段代码有点类似,抽象为一个高阶函数,放到IIFE里
const genExecInitFn = (obj, result, settledName) => (val) => {
if(status.get(obj) === PENDING) {
status.set(obj, settledName)
result.set(obj, val)
setTimeout(() => {
const cbs = callbacks.get(obj)
const len = cbs.length
for(let i = 0; i < len; i++) {
cbs[i][`on${settledName}`](val)
}
})
}
}
在constuctor里调用这个高阶函数
const resolve = genExecInitFn(this, value, FULFILLED)
const reject = genExecInitFn(this, reason, REJECTED)
实现then方法
class {
then(onFulfilled, onRejected) {
if(this.status === FULFILLED) {
setTimeout(() => { // 模拟Promise推入任务队列
onFulfilled(value.get(this)) // 标记1
})
}
if(this.status === REJECTED) {
setTimeout(() => { // 模拟Promise推入任务队列
onRejected(reason.get(this)) // 标记2
})
}
if(this.status === PENDING) {
callbacks.get(obj).push({
onFulfilled(value) {
onFulfilled(value.get(this)) // 标记3
},
onRejected(reason) {
onRejected(reason.get(this)) // 标记4
}
})
}
}
}
这里还有好多细节没实现,比如then方法会返回一个新的Promise
class {
then(onFulfilled, onRejected) {
return new MyPromise()
}
}
比如,如果onFulfilled和onRejected也返回Promise,新的Promise的resolve和reject做为这个Promise的then入参
class {
then(onFulfilled, onRejected) {
return new MyPromise((nextFulfilled, nextRejected) => {
const result = onFulfilled(value.get(this)) // onRejected也是如此
if(result instanceof MyPromise) {
result.then(nextFulfilled, nextRejected)
} else {
nextFulfilled(result)
}
})
}
}
比如,这个Promise还不能引用循环
class {
then(onFulfilled, onRejected) {
const promise = new MyPromise((nextFulfilled, nextRejected) => {
const result = onFulfilled(value.get(this)) // onRejected也是如此
if(promise === result) {
throw new TypeError('Chaining cycle detected for promise')
}
})
return promise
}
}
以上都是为了能链式调用,标记1到4都要这样,所以封装成一个函数,放到IIFE里
const handlePromise = (promise, result, nextFulfilled, nextRejected) => {
if(promise === result) {
throw new TypeError('chaining cycle!')
}
try {
if(result instanceof MyPromise) {
result.then(nextFulfilled, nextRejected)
} else {
nextFulfilled(result)
}
} catch(error) {
nextRejected(error)
}
}
把then的这一大块也放到一个函数里吧
const run = (obj, onFulfilled, onRejected) => {
const promise = new MyPromise((nextFulfilled, nextRejected) => {
if(status.get(obj) === FULFILLED) {
setTimeout(() => handlePromise(promise, onFulfilled(value.get(obj)), nextFulfilled, nextRejected))
}
if(status.get(obj) === REJECTED) {
setTimeout(() => handlePromise(promise, onRejected(reason.get(obj)), nextFulfilled, nextRejected))
}
if(status.get(obj) === PENDING) {
callbacks.get(obj).push({
[`on${FULFILLED}`]: () => handlePromise(promise, onFulfilled(value.get(obj)), nextFulfilled, nextRejected),
[`on${REJECTED}`]: () => handlePromise(promise, onRejected(reason.get(obj)), nextFulfilled, nextRejected)
})
}
})
return promise
}
还有就是,onFulfilled和onRejected无论如何都要是个函数
const genFn = (fn) => {
if(typeof fn !== 'function') {
return value => value
} else {
return fn
}
}
然后完整的then方法如下
class {
then(onFulfilled, onRejected) {
onFulfilled = genFn(onFulfilled)
onRejected = genFn(onRejected)
return run(this, onFulfilled, onRejected)
}
}
实现catch方法
这个就比较简单了,复用then的逻辑
class {
catch(onRejected) {
return this.then(null, onRejected)
}
}
实现静态方法resolve和reject
这个也比较简单
class {
static resolve(val) {
return new MyPromise((resolve, reject) => val instanceof MyPromise? val.then(resolve, reject): resolve(val))
}
static reject(val) {
return new MyPromise((resolve, reject) => reject(val))
}
}
实现静态方法all和race
首先他们是肯定都返回Promise,都传入Promise数组,all是所有都fulfilled后,这个Promise才fulfilled,而race只要一个就行
const genExecParamsAll = (promises) => (resolve, reject) => {
try {
const len = promises.length
const res = new Array(len).fill(void 0)
let count = 0
for(let i = 0; i < len; i++) {
promises[i].then((val) => {
res[i] = val
count = count + 1
if(count >= len) {
resolve(res)
}
}).catch(reject)
}
} catch(error) {
reject(error)
}
}
const genExecParamsRace = (promises) => (resolve, reject) => {
try {
const len = promises.length
for(let i = 0; i < len; i++) {
promises[i].then(resolve).catch(reject)
}
} catch(error) {
reject(error)
}
}
class {
static all(promises) {
return new MyPromise(genExecParamsAll(promises))
}
static race(promises) {
return new MyPromise(genExecParamsRace(promises))
}
}
最后,完整代码如下
const MyPromise = (() => {
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const status = new WeakMap()
const value = new WeakMap()
const reason = new WeakMap()
const callbacks = new WeakMap()
const genExecInitFn = (obj, result, settledName) => (val) => {
if(status.get(obj) === PENDING) {
status.set(obj, settledName)
result.set(obj, val)
setTimeout(() => {
const cbs = callbacks.get(obj)
const len = cbs.length
for(let i = 0; i < len; i++) {
cbs[i][`on${settledName}`](val)
}
})
}
}
const genFn = (fn) => {
if(typeof fn !== 'function') {
return value => value
} else {
return fn
}
}
const run = (obj, onFulfilled, onRejected) => {
const promise = new MyPromise((nextFulfilled, nextRejected) => {
if(status.get(obj) === FULFILLED) {
setTimeout(() => handlePromise(promise, onFulfilled(value.get(obj)), nextFulfilled, nextRejected))
}
if(status.get(obj) === REJECTED) {
setTimeout(() => handlePromise(promise, onRejected(reason.get(obj)), nextFulfilled, nextRejected))
}
if(status.get(obj) === PENDING) {
callbacks.get(obj).push({
[`on${FULFILLED}`]: () => handlePromise(promise, onFulfilled(value.get(obj)), nextFulfilled, nextRejected),
[`on${REJECTED}`]: () => handlePromise(promise, onRejected(reason.get(obj)), nextFulfilled, nextRejected)
})
}
})
return promise
}
const handlePromise = (promise, result, nextFulfilled, nextRejected) => {
if(promise === result) {
throw new TypeError('chaining cycle!')
}
try {
if(result instanceof MyPromise) {
result.then(nextFulfilled, nextRejected)
} else {
nextFulfilled(result)
}
} catch(error) {
nextRejected(error)
}
}
const genExecParamsAll = (promises) => (resolve, reject) => {
try {
const len = promises.length
const res = new Array(len).fill(void 0)
let count = 0
for(let i = 0; i < len; i++) {
promises[i].then((val) => {
res[i] = val
count = count + 1
if(count >= len) {
resolve(res)
}
}).catch(reject)
}
} catch(error) {
reject(error)
}
}
const genExecParamsRace = (promises) => (resolve, reject) => {
try {
const len = promises.length
for(let i = 0; i < len; i++) {
promises[i].then(resolve).catch(reject)
}
} catch(error) {
reject(error)
}
}
return class {
constructor(executor) {
status.set(this, PENDING)
value.set(this, null)
reason.set(this, null)
callbacks.set(this, [])
const resolve = genExecInitFn(this, value, FULFILLED)
const reject = genExecInitFn(this, reason, REJECTED)
try {
executor(resolve, reject)
} catch(error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = genFn(onFulfilled)
onRejected = genFn(onRejected)
return run(this, onFulfilled, onRejected)
}
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(val) {
return new MyPromise((resolve, reject) => val instanceof MyPromise? val.then(resolve, reject): resolve(val))
}
static reject(val) {
return new MyPromise((resolve, reject) => reject(val))
}
static all(promises) {
return new MyPromise(genExecParamsAll(promises))
}
static race(promises) {
return new MyPromise(genExecParamsRace(promises))
}
}
})()