关于Promise的定义,promise是什么,大家可自行翻阅阮一峰-《ECMAScript 6》
废话不多,直接上代码
Promise的基本用法
new MyPromise((resolve, reject) => {
resolve(1)
}).then((v) => {
console.log(v)
})参考以上Promise的基本用法,我们基本确定我们代码的大体结构,
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECT = 'reject'
function MyPromise(fn){
let that = this
that.state = PENDING that.value = null
that.resolvedCallbacks = []
that.rejectCallbacks = []
}
MyPromise.prototype.then = function(onresolved, onreject) {
}- 首先,初始化三个状态,使用常量来保存着三个状态,便于后期的维护和管理;
- 声明that保存this指向,在之后的代码中可能存在异步调用,以确保this指向的正确性;
- 初始化状态state为pending;
- 创建value属性,来保存resolve和reject传入的值;
- 创建resolvedCallbacks 和rejectCallbacks用于保存在then方法中的回调函数,在状态变化调用,因为有可能在MyPromise执行完之后,状态还未改变;
- 在MyPromise的原型对象上创建then方法;
接下来,我们继续完善resolve,reject方法,在MyPromise函数体中
function resolve(value) {
if(that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value))
}
}
function reject(value) {
if(that.state === PENDING) {
that.state = REJECT
that.value = value
that.rejectCallbacks.map(cb => cb(that.value))
}
}- resolve和reject都需要判断state是否为等待中,因为只有在state为等待中时,才能改变状态;
- 改变状态为对应状态,将value赋给that.value
- 遍历调用回调数组
执行fn,在MyPromise函数体中
try{
fn(resolve, reject)
}catch(e) {
reject(e)
}- 将resolve,reject作为fn的参数,传入fn;
- 使用try{}catch(){}捕获执行fn时的错误;
最后,我们来实现较为复杂的then函数
MyPromise.prototype.then = function(onResolved, onReject) {
let that = this
onResolved = typeof onResolved === 'function' ? onResolved : v => v
onReject = typeof onReject === 'function' ? onReject : r => {throw r}
if(that.state === PENDING) {
that.resolvedCallbacks.push(onResolved)
that.rejectCallbacks.push(onReject)
}
if(that.state === RESOLVED) {
onResolved(that.value)
}
if(that.state === REJECT) {
onReject(that.value)
}
}- 首先判断两个参数是否为函数,因为这两个参数为非必填参数
- 之后根据每种状态,执行不同操作
以上就是简单版的Promise的思路和实现;
之后会继续更新符合promise/A+规范的promise,大家可以先了解下promise/A+规范
以下为本次实现的完整代码
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECT = 'reject'
function MyPromise(fn) {
let that = this
that.state = PENDING
that.value = null
that.resolvedCallbacks = []
that.rejectCallbacks = []
function resolve(value) {
if(that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(value))
}
}
function reject(value) {
if(that.state === PENDING) {
that.state = REJECT
that.value = value
that.rejectCallbacks.map(cb => cb(value))
}
}
try {
fn(resolve, reject)
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onResolved, onReject) {
const that = this
onResolved = typeof onResolved === 'function' ? onResolved : v => v
onReject = typeof onReject === 'function' ? onReject : r => { throw r }
if(that.state === PENDING) {
that.resolvedCallbacks.push(onResolved)
that.rejectCallbacks.push(onReject)
}
if(that.state === RESOLVED) {
onResolved(that.value)
}
if(that.state === REJECT) {
onReject(that.value)
}
}