前言
百度了很多次别人写的promise ,也是一时兴起 今天自己写了一个并且做了这么一个记录
Promises/A+
同学们:此处自行查阅Promises/A+规范
Just do it
接下来我根据我自己习惯看规范
“promise” is an object or function with a then method whose behavior conforms to this specification.
class Promise{}和function Promise{} 都行,那我写的是class
class Promise{
constructor(execuctor) {}
}
export default Promise
-
A promise must be in one of three states: pending, fulfilled, or rejected....
每个promise 都有三个状态 ,且pedding状态时可变更(通过resolve和reject) fulfilled, or rejected,但只支持变更一次,不能转变成任何其他状态。 -
“reason” is a value that indicates why a promise was rejected.
“value” is any legal JavaScript value (including undefined, a thenable, or a promise).
resolve() 和reject() 的参数 和其值的初始化,结合2做状态变更处理
//状态常量
/**初始化状态*/
const PENDING = "PENDING";
/**成功状态*/
const FULFILLED = "FULFILLED";
/**失败状态*/
const REJECTED = "REJECTED";
class Promise{
constructor(execuctor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (val) => {
// 状态变更后 不可以在更改为其他状态,只支持修改一次
if (this.status === PENDING) {
this.value = val; //成功状态时 value的赋值
this.status = FULFILLED; //修改状态
}
};
const reject = (err) => {
// 状态变更后 不可以在更改为其他状态,只支持修改一次
if (this.status === PENDING) {
this.reason = err; //失败状态时的 reason的赋值
this.status = REJECTED; //修改状态
}
}
}
“exception” is a value that is thrown using the throw statement.
throw 语句抛出的异常。这里按照我自己的理解 用try,catch 捕获异常的时候 调用reject(err)
try {
execuctor(resolve, reject);
} catch (err) {
reject(err);
}
A promise’s then method accepts two arguments: promise.then(onFulfilled, onRejected)....
then 方法的支持,FULFILLED执行onFulfilled,REJECTED执行onRejected而且参数均得是函数,这里规范我们没有全部粘贴
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onRejected(this.reason);
}
- promise的解决问题是异步回调地狱的问题,当前的实现还是同步执行,如果遇到setTimeout包裹resolve 延迟执行,那then拿到的status会一直是pending,无法执行对应函数
- 🌰
let promise = new Promise((resolve, reject) => {
console.log("promise begin");
setTimeout(() => {
resolve("成功");
}, 1000);
});
promise.then(
//无法打印,因为计时器执行完后then早就执行完了所以then里拿到的状态始终是pending
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
- 解决:执行到then里的时候将回调函数缓存在数组里,结合发布订阅模式 统一做发布
constructor(){
//构造器里新增两个数组做缓存
this.onFulfilledCallback=[]
this.onRejectedCallback=[]
}
//修改then的实现,执行then的时候 做onFulfilled,onRejected,push进缓存数组的操作
then(onFulfilled, onRejected) {
if (this.status === PENDING) {
this.onFulfilledCallback.push(() => {
onFulfilled(this.value);
});
this.onRejectedCallback.push(() => {
onRejected(this.reason);
});
}
}
//resolve方法里 新增 遍历onFulfilledCallback 数组并执行
this.onFulfilledCallback.forEach(fn=>fn())
//reject方法里 同理
this.onRejectedCallback.forEach(fn=>fn())
- 重新执行上面setTimeout的例子 这时候就可以 正常打印了
then may be called multiple times on the same promise..... then must return a promise promise2 = promise1.then(onFulfilled, onRejected);....
- then方法返回一个promise对象用于链式调用
- then里接受到的状态是上一个then的执行成功与否状态
- 如果是成功就调用成功回调函数,如果是失败就调用失败回调函数..
- 上一个then执行结果x作为当前return的整个promise的resolve()和reject()的入参
then(onFulfilled, onRejected) {
//返回一个promise对象实现链式调用,包裹原来的then内部代码先
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (err) {
reject(err);
}
}
if (this.status === REJECTED) {
try {
// 上一个then执行结果x作为当前then的resolve的入参数
let x = onRejected(this.reason);
resolve(x);
} catch (err) {
reject(err);
}
}
if (this.status === PENDING) {
//异步调用
this.onFulfilledCallback.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (err) {
reject(err);
}
}, 0);
});
this.onRejectedCallback.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolve(x);
} catch (err) {
reject(err);
}
}, 0);
});
}
}
}
测试
-
写到这里 基本功能 reject ,resolve ,和then的链式调用 基本 实现
-
代码测试插件用的是 code run (按照指南[VS code插件分享之 --- Run Code]
- 测试结果
完整代码
//状态常量
/**初始化状态*/
const PENDING = "PENDING";
/**成功状态*/
const FULFILLED = "FULFILLED";
/**失败状态*/
const REJECTED = "REJECTED";
class Promise {
constructor(execuctor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (val) => {
// 状态变更后 不可以在更改为其他状态,只支持修改一次
if (this.status === PENDING) {
this.value = val; //成功状态时 value的赋值
this.status = FULFILLED; //修改状态
}
};
const reject = (err) => {
// 状态变更后 不可以在更改为其他状态,只支持修改一次
if (this.status === PENDING) {
this.reason = err; //失败状态时的 reason的赋值
this.status = REJECTED; //修改状态
}
};
try {
execuctor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
//1.返回一个promise对象实现链式调用
let promise2 = new Promise((resolve, reject) => {
//2.支持then调用后 then里接受到的状态是上一个then的执行成功与否状态
// 所以 this.status 在这时候就不仅有PENDING了
if (this.status === FULFILLED) {
// 3.函数执行时的throw Error的处理,同理将所有的都加上错误捕获
try {
let x = onFulfilled(this.value);
// 上一个then执行结果x作为当前then的resolve的入参数
// 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject
resolve(x);
} catch (err) {
reject(err);
}
}
if (this.status === REJECTED) {
try {
// 上一个then执行结果x作为当前then的reject的入参数
let x = onRejected(this.reason);
// 这里要注意 只要上一个then有return 值 就调用当前then的resolve 捕获了异常才调用reject
resolve(x);
} catch (err) {
reject(err);
}
}
// 4. 为了支持链式调用 第一次的then也要将执行结果x 传给对应的resolve或者reject
if (this.status === PENDING) {
//异步调用
this.onFulfilledCallback.push(() => {
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (err) {
reject(err);
}
});
this.onRejectedCallback.push(() => {
try {
let x = onRejected(this.reason);
resolve(x);
} catch (err) {
reject(err);
}
});
}
});
return promise2;
}
}
export default Promise
小结
到这里就写完了一个简易支持then链式调用promise的全部代码 promise2.0