最近学习了 promise 的实现,所以写篇博客记录下自己的收获,也可以加深自己的理解和记忆
什么是promise?
Promise 是 es6 新增的对象,其主要功能是处理异步操作,通过实例化对象来管理异步状态,及then方法处理异步结果
来看看其用法
new Promise((resolve, reject) ==> {
// 伪代码
ajax((res) => {
if (res.code === 200) {
// 成功状态,调用resolve
resolve(res.data)
} else {
// 失败状态,调用reject
reject(res)
}
})
}).then((data) => {
// 处理成功状态
}, () => {
// 处理失败状态
})
可以看到在 promise 中,我们通过调用 resolve reject 来更改异步状态及传递异步结果,然后在 then 函数中处理异步结果。不同于使用回调函数来处理异步结果的方法,promise 通过使用 then 来处理异步结果,同时可以使用链式调用来一步步处理结果,例如
new Promise().then().then().then()
其中在 then 函数也可以创建新的 promise 来进行异步操作
new Promise().then(() => { return new Promise() }).then().then()
promise的实现
promiseA+规范
看网上的实现文章很多都谈到了 promiseA+,这是个什么东东呢?
看看官网怎么写的
An open standard for sound, interoperable JavaScript promises—by implementers, for implementers
一个开放,健全且通用的 Javascript Promise 标准。由开发者制定,供开发者参考
可以看出,promiseA+就是份指导 promise 实现的规范,它定义了 promise 的状态,如何改变状态,then 方法的使用及返回值。
可以说,只有写出了符合 promiseA+ 的 promise 才是真正实现了 promise
实现代码
直接贴出全部代码吧,毕竟是抄其它大佬的
// promise的唯三状态
// 等待异步结果
const PENDING = 'pending'
// 执行状态
const FULFILLED = 'fulfilled'
// 拒绝状态
const REJECTED = 'rejected'
function MyPromise(exector) {
this.status = PENDING
// 等待异步结果的待执行函数(实现then的链式调用)
// promise执行队列
this.fulfilledList = []
// promise拒绝队列
this.rejectedList = []
// 参数 resolve
const resolve = value => {
if (this.status === PENDING) {
// 改变状态为执行状态
this.status = FULFILLED
this.value = value
// 异步执行执行队列
setTimeout(() => {
this.fulfilledList.forEach((fn) => {
fn()
})
})
}
}
const reject = reason => {
if (this.status === PENDING) {
// 改变状态为拒绝状态
this.status = REJECTED
this.reason = reason
// 异步执行拒绝状态
setTimeout(() => {
this.rejectedList.forEach((fn) => {
fn()
})
})
}
}
try {
// 执行传入参数exector
exector(resolve, reject)
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
// 成功和失败的处理函数,如果没有对应的处理函数则将值和状态传递下去
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
let promise2 = null
// 规范规定了then的返回值是新promise2,这是实现 then 的链式调用的基础
// 返回值 promise2 的状态并不依赖于 promise 的状态
// 其状态由处理函数 onFulfilled onRejected 及其执行的返回结果决定(可能是 执行状态 拒绝状态 等待状态)
// 所以 new Promise().then().then() 中有可能出现第一个then执行拒绝函数和第二个then执行执行函数
// 可以说,第二个then完全依赖于上一个then,和最初的promise没有关系
promise2 = new MyPromise((resolve, reject) => {
// promise已经是执行状态
if (this.status === FULFILLED) {
setTimeout(() => {
// 异常则更改promise为拒绝状态
try {
// 执行函数获得结果x
const x = onFulfilled(this.value)
// 执行promise解决程序
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// 异常则更改promise为拒绝状态
if (this.status === REJECTED) {
setTimeout(() => {
// 异常则拒绝
try {
// 可以看出,只要onFulfilled 和 onRejected 正常执行了就会走promise处理程序,否则就会reject
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// promise还处于等待状态
if (this.status === PENDING) {
// 同时往执行和拒绝队列中添加处理函数,此时不知道后面的状态及会最终会执行的队列
this.fulfilledList.push(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.rejectedList.push(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
// 返回新的promise
return promise2
}
// promise的解决程序
// 大概为以下解决思路,主要就是判断x是不是promise或者是否有then方法,如果是则获取x状态(执行x.then递归promise解决程序),否则直接resolve(x)
// 1. 判断x是否和promise为同一个对象,是则reject(类型错误)
// 2. 判断x是否为Promise实例,是则将x的状态作为promise的状态,实际就是执行x.then获取x的状态及结果来递归执行promise解决程序
// 3. 判断x是否为函数或对象,如果是x.then是函数则执行then获取x的状态及结果来递归执行promise解决程序
// 4. 如何x不是对象或者x.then不是函数,则resolve(x)
function resolvePromise (promise, x, resolve, reject) {
// x 和 promise 相等则 reject 类型错误
if (x === promise) {
return reject(new TypeError('cycle chain'))
}
// x 是个promise
if (x instanceof MyPromise) {
// 将x的状态作为promise的状态,如何获取x的状态,通过then方法
x.then(y => {
// 继续执行promise解决程序
resolvePromise(promise, y, resolve, reject)
}, reject)
} else if (x && (typeof x === 'object' || typeof x === 'function')) {
let then = null
// 防止重复调用
let used = false
// 规范定义的,取then错误则reject
try {
then = x.then
} catch (e) {
reject(e)
}
// 如果x.then是个函数
if (typeof then === 'function') {
try {
// 执行then,使用then的状态作为promise状态
then.call(x, y => {
if (used) return
used = true
resolvePromise(promise, y, resolve, reject)
}, r => {
if (used) return
used = true
reject(r)
})
} catch(e) {
if (used) return
reject(e)
}
} else {
// 普通对象,resolve
if (used) return;
resolve(x)
}
} else {
// x 不是对像或函数 resolve
resolve(x)
}
}
以上便是一个符合 promiseA+ 规范的 promise 实现,口说无凭,如何证明它符合规范呢?
测试
可以使用官方测试工具 promises-aplus-tests
安装
npm install promises-aplus-tests -g
为你实现的 promise 添加 deferred
方法
MyPromise.deferred = function() {
var result = {};
result.promise = new MyPromise(function(resolve, reject){
result.resolve = resolve;
result.reject = reject;
});
return result;
}
模块化导出 promise
module.exports = MyPromise
运行测试脚本
promises-aplus-tests <File>
参考
欢迎到前端学习打卡群一起学习~516913974