经常在面试题中会看到,让你实现一个Promsie,或者问你实现Promise的原理,所以今天就尝试利用class类的形式来实现一个Promise
为了不与原生的Promise命名冲突,这里就简单命名为MyPromise.
class Promise {
constructor(executor) {
const self = this
self.state = 'pending'
self.value = null
self.reason = null
self.onFulfilledFunc = []
self.onRejectedFunc = []
function resolve(value) {
if (self.state === 'pending') {
self.value = value
self.state = 'resolved'
self.onFulfilledFunc.forEach(fn => fn(value))
}
}
function reject(reason) {
if (self.state === 'pending') {
self.reason = reason
self.state = 'rejected'
self.onRejectedFunc.forEach(fn => fn(reason))
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected =
typeof onRejected === 'function'
? onRejected
: err => {
throw err
}
let self = this
let promise2
switch (self.state) {
case 'resolved':
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
break
case 'rejected':
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
break
case 'pending':
promise2 = new Promise((resolve, reject) => {
self.onFulfilledFunc.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
self.onRejectedFunc.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
})
break
default:
break
}
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(fn) {
this.then(() => {
fn()
}, () => {
fn()
})
return this
}
static resolve(value) {
return new Promise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new Promise(reject => {
reject(reason)
})
}
static all(values) {
return new Promise((resolve, reject) => {
const result = []
let index = 0
function keyToArr(key, value) {
index++
result[key] = value
if (index === values.length) {
resolve(result)
}
}
for (let i = 0; i < values.length; i++) {
let current = values[i]
if (current !== null && (typeof current === 'object' || typeof current === 'function')) {
let then = current.then
if (typeof then === 'function') {
then(value => {
keyToArr(i, value)
}, e => {
reject(e)
})
} else {
keyToArr(i, current)
}
} else {
keyToArr(i, current)
}
}
})
}
static race(values) {
return new Promise((resolve, reject) => {
for (let i = 0; i < values.length; i++) {
const current = values[i]
if (current !== null && (typeof current === 'object' || typeof current === 'function')) {
let then = current.then
if (typeof then === 'function') {
then(resolve, reject)
} else {
resolve(current)
}
} else {
resolve(current)
}
}
})
}
static deferred() {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Promise循环引用'))
}
let isUsed // 确保resolve或者rejected后,状态不会再次发生变更
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (isUsed) return
isUsed = true
resolvePromise(promise2, y, resolve, reject)
}, e => {
if (isUsed) return
isUsed = true
reject(e)
})
} else {
if (isUsed) return
isUsed = true
resolve(x)
}
} catch (e) {
if (isUsed) return
isUsed = true
reject(e)
}
} else {
resolve(x)
}
}
module.exports = Promise
检测是否完全符合Promise/A+规范
npm install -g promises-aplus-tests
具体用法请看promise test然后
promises-aplus-tests myPromise.js
结果真香: