「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战」
Javascript Promise的简单模拟实现
promise可以说是前端工程师必备的技术点了。之前不管是面试还是开发中经常有用到promise,有些特性也是一边学一边忘。通过对promise的简单模拟实现了解其原理,可能会对promise更加深刻。可能不是特别完美,主要还是做一个学习交流。
一、promise的特点和功能
在实现之前,我们先来梳理一下promise的特点和功能,看看具体要实现哪些功能,一步一步拆解开来实现。
- 属性:
- 状态(state)
- 值(value)
- 回调函数列表
- 方法:
实例方法:
- executor 执行器调用
- resolve,reject
原型方法:
- then
- catch
静态方法: - resolve,reject
- all,race
二、实现步骤
1. 构造器
首先先来实现构造器,在构造器中主要是定义了实例属性和实例方法,也就是上面提到的:
- 状态(state)
- 值(value)
- 回调函数列表
- executor 执行器调用
- resolve,reject
回顾一下这些的特点
- promise对象有三种状态,
pending
,resolved
,rejected
- 状态只有两种变化方向,
pending
=>resolved
,pending
=>rejected
,而且状态一旦更改就不能再改变。 - 值的变化也是随着状态的改变而发生改变的,所以值也只能改变一次。
- 执行器是在构造函数中同步调用的。
- resolve和reject分别会作为参数传入执行器中。
- 在执行器中调用resolve和reject方法可以将promise对象的状态分别改变为
resolved
,rejected
根据上面的特点可以简单实现一个构造器
class _Promise {
//构造方法
constructor(executor) {
const that = this
that.state = PENDING;
that.value = undefined;
that.resolvedCallbacks = []
that.rejectedCallbacks = []
//resolve 函数
function resolve(data) {
if (val instanceof _Promise) {
return val.then(that.resolve, that.reject)
}
setTimeout(() => {
if (that.state === PENDING) {
that.state = RESOLVED
that.value = val
that.resolvedCallbacks.map(callback => callback(val))
}
}, 0)
}
//reject 函数
function reject(data) {
setTimeout(() => {
if (that.state === PENDING) {
that.state = REJECTED
that.value = val
that.rejectedCallbacks.map(callback => callback(val))
}
}, 0)
}
try {
//同步调用『执行器函数』
executor(resolve, reject);
} catch (e) {
//修改 promise 对象状态为『失败』
reject(e);
}
}
}
原型方法 then,catch
来梳理一下then和catch的特点
- promsie的一个特点是链式调用,为了实现这个then和catch方法返回的都是一个新的promise对象。
- then方法的功能主要是注册或执行回调函数
- 若promise实例的状态是
pending
,则将回调函数注册到promise实例的回调函数列表中 - 若promise实例的状态发生了改变,为
resolved
或rejected
,则直接执行对应的回调函数。
- then的两个参数可以传也可以不传,如果传了必须是函数类型,所以需要做一个兜底提高兼容性。
- catch方法其实就是特殊的then方法,catch(onRejected) = then(undefined, onRejected);
then(onfullfilled, onrejected) {
let that = this
let p2
onfullfilled = typeof onfullfilled === `function` ? onfullfilled : v => v
onrejected = typeof onrejected === `function` ? onrejected : v => { throw v }
if (that.state === PENDING) {
return (p2 = new _Promise((resolve, reject) => {
that.resolvedCallbacks.push(() => {
onfullfilled(that.value)
resolve()
})
that.rejectedCallbacks.push(() => {
onrejected(that.value)
reject()
})
}))
}
if (that.state === RESOLVED) {
return (p2 = new _Promise((resolve, reject) => {
onfullfilled(that.value)
resolve()
}))
}
if (that.state === REJECTED) {
return (p2 = new _Promise((resolve, reject) => {
onrejected(that.value)
reject()
}))
}
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
3. 静态方法 resolve,reject,all,race
这里的resolve和reject和刚刚提到的是不同的函数。 来梳理一下这几个静态方法的特点
-
resolve和reject方法直接返回一个状态已变化且值为函数参数的promise实例
-
all和race方法返回的也是一个新的promise实例,但是这个promise实例的状态的确定方式不同
-
all 方法在传入的所有promise实例的状态都为
resolved
时返回的新的promise实例的状态才是resolved
,否则都是rejected
。
race 方法顾名思义,只要传入的promise实例中有一个状态发生改变,就进行返回,并且返回的新的promise实例的值和状态都和该promise实例保持一致。
//添加 resolve 方法
static resolve(value) {
//返回promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
//添加 all 方法
static all(promises) {
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for (let i = 0; i < promises.length; i++) {
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象 都成功
count++;
//将当前promise对象成功的结果 存入到数组中
arr[i] = v;
//判断
if (count === promises.length) {
//修改状态
resolve(arr);
}
}, r => {
reject(r);
});
}
});
}
//添加 race 方法
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
}, r => {
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
}
三、完整的代码
const PENDING = `pending`
const RESOLVED = `resolved`
const REJECTED = `rejected`
class _Promise {
//构造方法
constructor(executor) {
const that = this
that.state = PENDING;
that.value = undefined;
that.resolvedCallbacks = []
that.rejectedCallbacks = []
//resolve 函数
that.resolve = function (val) {
if (val instanceof _Promise) {
return val.then(that.resolve, that.reject)
}
setTimeout(() => {
if (that.state === PENDING) {
that.state = RESOLVED
that.value = val
that.resolvedCallbacks.map(callback => callback(val))
}
}, 0)
}
//reject 函数
that.reject = function (val) {
setTimeout(() => {
if (that.state === PENDING) {
that.state = REJECTED
that.value = val
that.rejectedCallbacks.map(callback => callback(val))
}
}, 0)
}
try {
//同步调用『执行器函数』
fn(that.resolve, that.reject)
} catch (error) {
//修改 promise 对象状态为『失败』
that.reject(error)
}
}
//then 方法封装
then(onfullfilled, onrejected) {
let that = this
let p2
onfullfilled = typeof onfullfilled === `function` ? onfullfilled : v => v
onrejected = typeof onrejected === `function` ? onrejected : v => { throw v }
if (that.state === PENDING) {
return (p2 = new _Promise((resolve, reject) => {
that.resolvedCallbacks.push(() => {
onfullfilled(that.value)
resolve()
})
that.rejectedCallbacks.push(() => {
onrejected(that.value)
reject()
})
}))
}
if (that.state === RESOLVED) {
return (p2 = new _Promise((resolve, reject) => {
onfullfilled(that.value)
resolve()
}))
}
if (that.state === REJECTED) {
return (p2 = new _Promise((resolve, reject) => {
onrejected(that.value)
reject()
}))
}
}
//catch 方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
//添加 resolve 方法
static resolve(value) {
//返回promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
//添加 all 方法
static all(promises) {
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for (let i = 0; i < promises.length; i++) {
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象 都成功
count++;
//将当前promise对象成功的结果 存入到数组中
arr[i] = v;
//判断
if (count === promises.length) {
//修改状态
resolve(arr);
}
}, r => {
reject(r);
});
}
});
}
//添加 race 方法
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
}, r => {
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
}
小白的简单实现,如果要符合promise的A+规范,可能还要做非常多优化,欢迎大佬们提出建议。