先给大家回忆下promise的基础使用
// 创建一个 Promise 对象
const myPromise = new MyPromise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
// const randomNumber = Math.random();
const randomNumber = 0.2;
console.log(randomNumber);
if (randomNumber > 0.5) {
// 异步操作成功,调用 resolve 并传递结果
resolve(randomNumber);
} else {
// 异步操作失败,调用 reject 并传递错误信息
reject(new Error("异步操作失败"));
}
}, 2000);
});
// 使用 Promise 对象
myPromise
.then((result) => {
// 异步操作成功后的处理
console.log("成功:", result);
}, (error) => {
// 异步操作失败后的处理
console.log("失败:", error);
});
接下来开始手写promise 第一步就是要先定义状态
const PENDING = "pending";
const RESOLVE = "resolve";
const REJECT = "reject";
第二步就是执行传入的promise参数的函数fn
function MyPromise(fn) {
//将两个回调函数传入,并执行函数
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
第三步初始化内部变量
//保存初始状态,value用于保存resolve或reject函数传入的参数
let self = this;
this.value = null;
this.status = PENDING;
//存储then中的resolve,reject的回调函数
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
第四步,定义resolve,和reject函数
function resolve(value) {
//如果参数是promise,则状态改变必须等待前一个状态改变后
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
//使得在then函数中完成resolve或reject注册后再进行调用这里
setTimeout(() => {
if (self.status === PENDING) {
self.status = RESOLVE;
self.value = value;
self.resolvedCallbacks.forEach(callback => {
callback(value);
})
}
}, 0)
}
function reject(value) {
setTimeout(() => {
if (self.status === PENDING) {
self.status = REJECT;
self.value = value;
self.rejectedCallbacks.forEach(callback => {
callback(value);
})
}
}, 0)
}
第五步,为promise添加then方法
MyPromise.prototype.then = function(onResolved, onRejected) {
//因为是可选参数,所以先判断参数类型
onResolved = typeof onResolved === 'function' ? onResolved : function(value) { return value };
onRejected = typeof onRejected === 'function' ? onRejected : function(value) { return value };
//如果是等待状态,就加入函数队列,既注册函数
if (this.status === PENDING) {
this.resolvedCallbacks.push(onResolved);
this.rejectedCallbacks.push(onRejected);
}
//如果不是等待状态就直接执行函数
if (this.status === RESOLVE) {
onResolved(this.value);
}
if (this.status === REJECT) {
onRejected(this.value);
}
}
这样一个基础的promise就完成了,让我觉得比较有意思的是resolve和reject函数中的setTimeout的使用,这里为什么要使用setTimeout呢,因为我们一般是这样用promise的
const myPromise = new MyPromise((resolve, reject) => {
resolve(111);
});
myPromise
.then((result) => {
console.log("成功:", result);
});
如果不给resolve加setTimeout的话,在同步线程里,resolve函数就会先执行,那resolve里运行 self.resolvedCallbacks.forEach(callback => { callback(value); })时就会找不到回调函数,因此必须把这个操作放入异步队列里,保证它是本轮循环最后执行的代码。
完整代码
//定义状态
const PENDING = "pending";
const RESOLVE = "resolve";
const REJECT = "reject";
function MyPromise(fn) {
//保存初始状态,value用于保存resolve或reject函数传入的参数
let self = this;
this.value = null;
this.status = PENDING;
//存储then中的resolve,reject的回调函数
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
function resolve(value) {
//如果参数是promise,则状态改变必须等待前一个状态改变后
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
//使得在then函数中完成resolve或reject注册后再进行调用这里
setTimeout(() => {
if (self.status === PENDING) {
self.status = RESOLVE;
self.value = value;
self.resolvedCallbacks.forEach(callback => {
callback(value);
})
}
}, 0)
}
function reject(value) {
setTimeout(() => {
if (self.status === PENDING) {
self.status = REJECT;
self.value = value;
self.rejectedCallbacks.forEach(callback => {
callback(value);
})
}
}, 0)
}
//将两个回调函数传入,并执行函数
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
MyPromise.prototype.then = function(onResolved, onRejected) {
//因为是可选参数,所以先判断参数类型
onResolved = typeof onResolved === 'function' ? onResolved : function(value) { return value };
onRejected = typeof onRejected === 'function' ? onRejected : function(value) { return value };
//如果是等待状态,就加入函数队列,既注册函数
if (this.status === PENDING) {
this.resolvedCallbacks.push(onResolved);
this.rejectedCallbacks.push(onRejected);
}
//如果不是等待状态就直接执行函数
if (this.status === RESOLVE) {
onResolved(this.value);
}
if (this.status === REJECT) {
onRejected(this.value);
}
}