简易版 Promise
const PENDING = 'PENDING',
FULFILLED = 'FULFILLED',
REJECTED = 'REJECTED'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
executor(resolve, reject)
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = MyPromise
测试一下
const MyPromise = require('./MyPromise')
let promise = new MyPromise((resolve, reject) => {
resolve('success')
// reject('error')
})
promise.then(
(value) => {
console.log('Fulfilled', value) // Fulfilled success
},
(reason) => {
console.log('Rejected', reason) // Rejected error
}
)
但是当我们在实例中抛出错误的时候,MyPromise 没有自动捕获错误。
const MyPromise = require('./MyPromise')
let promise = new MyPromise((resolve, reject) => {
throw new Error('Error!') // 此时程序无法捕获错误
})
修改为 用 try { } catch (e) { } 捕获 executor 执行过程中的错误
......
class MyPromise {
......
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
......
}
module.exports = MyPromise
处理 Promise 中的异步和多次调用问题
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
promise.then(
(value) => {
console.log('Fulfilled', value) // **没有反应**
}
)
此时的 MyPromise 还不能处理异步的,增加程序的异步处理功能,我们需要用到订阅发布的程序设计模式。当处于 PENDING 状态的时候,收集成功和失败的回调函数,这个过程称为订阅过程,然后在 FULFILLED 状态或者 REJECTED 状态的时候,触发收集的回调函数,即发布过程。
......
class MyPromise {
constructor(executor) {
......
this.onFulfilledCallback = [] // 存储成功的回调函数
this.onRejectedCallback = [] // 存储失败的回调函数
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
for (let i = 0; i < this.onFulfilledCallback.length; i++) {
this.onFulfilledCallback[i]()
}
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
for (let i = 0; i < this.onRejectedCallback.length; i++) {
this.onRejectedCallback[i]()
}
}
}
......
}
then(onFulfilled, onRejected) {
......
if (this.status === PENDING) {
// 在PENDING状态收集回调函数,这个过程称为订阅的过程
this.onFulfilledCallback.push(() => {
onFulfilled(this.value)
})
this.onRejectedCallback.push(() => {
onRejected(this.reason)
})
}
}
}
测试一下,此时程序可以执行异步函数了
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
promise.then(
(value) => {
console.log('Fulfilled1', value)
},
(reason) => {
console.log('Rejected1', reason)
}
)
promise.then(
(value) => {
console.log('Fulfilled2', value)
},
(reason) => {
console.log('Rejected2', reason)
}
)
// Fulfilled1 success
// Fulfilled2 success
实现Promise 的链式调用功能
实现起来有点复杂,建议参照 Promises/A+ 规范,一步步实现就很清晰啦~
const PENDING = 'PENDING',
FULFILLED = 'FULFILLED',
REJECTED = 'REJECTED'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallback = [] // 存储成功的回调函数
this.onRejectedCallback = [] // 存储失败的回调函数
const resolve = (value) => {
if (value instanceof MyPromise) {
return value.then(resolve, reject)
}
setTimeout(() => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
for (let i = 0; i < this.onFulfilledCallback.length; i++) {
this.onFulfilledCallback[i]()
}
}
}, 0)
}
const reject = (reason) => {
setTimeout(() => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
for (let i = 0; i < this.onRejectedCallback.length; i++) {
this.onRejectedCallback[i]()
}
}
}, 0)
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) {
// 在PENDING状态收集回调函数,这个过程称为订阅的过程
// PENDING状态不用延时
this.onFulfilledCallback.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.onRejectedCallback.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
catch(errorCallback) {
return this.then(null, errorCallback)
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 按照 Promises/A+ 规范一步步实现
if (promise2 === x) {
return reject(new TypeError('circle!')) // 处理死循环
}
if (x instanceof MyPromise) {
if (this.status === PENDING) {
x.then((v) => {
resolvePromise(promise2, v, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
return
}
let called = false
if (
(x !== 'null' && typeof x === 'object') ||
typeof x === 'function'
) {
try {
let then = x.then
if (typeof then === 'function') {
// Promise
then.call(
x,
(y) => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
}
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
module.exports = MyPromise
实现过程可以参考B站这位大佬的视频 www.bilibili.com/video/BV1nV…
虽然 then 普遍认为是微任务。但是浏览器没办法模拟微任务,目前要么用 setImmediate ,这个也是宏任务,且不兼容的情况下还是用 setTimeout 打底的。还有,promise 的 polyfill (es6-promise) 里用的也是 setTimeout。因此这里就直接用 setTimeout,以宏任务来代替微任务了。 此段文字转自 juejin.cn/post/684490…