前言
嗯嗯嗯,等写完这个博客我就去复习期末。
实现过程
基本属性
对一个promise来说,我们需要有下面这些东西
- 对应三个状态的表示
- 当前promise的数据(也就是成功获得的数据或者失败的原因)
- 当前promise的状态
- 成功时要执行的回调函数列表
- 失败时要执行的回调函数列表
另外,为了使用属性私有化,我们要用一个立即执行函数来生成class,然后私有属性全部使用Symbol类型定义
const MyPromise = (function () {
// 对应的三个状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// 当前promise的数据
const PromiseValue = Symbol("PromiseValue");
// 当前promise的状态
const PromiseStatus = Symbol("PromiseStatus");
// 成功时要执行的回调函数列表
const onFulfilledList = Symbol("onFulfilledList");
// 失败时要执行的回调函数列表
const onRejectedList = Symbol("onRejectedList");
return class {
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
}
}
})();
可以看到我们把状态,数据,两个回调列表存到了promise上,然后我们就可以逐步实现一个promise了
完成基础版本
先看看promise最基础的用法
let promise = new Promise((resolve, reject) => {
resolve("sena");
});
我们可以看到,在new Promise时,会传入一个函数,这个函数会立即执行,这个函数接收两个参数,分别是resolve和reject,这两个函数是定义好的,这个函数做了下面几件事
- 改变当前promise的状态
- 把传入的参数作为当前promise的数据保存起来
- 执行对应回调列表里里的回调函数
另外要注意的是,promise的状态是不可逆的,只能从pending变成resolved或者rejected,不能倒回去,所以我们要先做个判断再改变状态。
因为修改状态为成功和失败的逻辑都是一致的,所以我们可以把逻辑抽象为一个私有的工具函数
const MyPromise = (function () {
// 上面已经有的重复代码
......
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
return class {
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue 新的 promise数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
// 如果状态不是pending, 就返回
if (this[PromiseStatus] !== PENDING) return;
// 把当前promise的状态改成新的状态
this[PromiseStatus] = newStatus;
// 把当前promise的值更新为新的值
this[PromiseValue] = newValue;
// 把回调列表里的函数取出来依次执行
executeQueue.forEach((handler) => {
// 把值传给回调函数执行
handler(newValue);
})
}
constructor(executor) {
.....
}
}
})();
好了,我们现在已经定义了一个工具函数[updateStatus],但这个工具函数还有一点不好的地方,那就是then绑定的回调函数都是放到微任务中异步执行的,而我们这里是同步执行,在浏览器环境下,没有办法把回调函数放到微任务中,只能放到宏任务队列中异步执行,所以我们还要再更新一下[updateStatus] 函数
因为把一个回调函数推入宏任务队列也可以抽象一下,所以我们写一个把回调函数推入任务队列的工具函数
const MyPromise = (function () {
......
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
// 把任务添加到宏任务队列里的函数
const executeAsync = Symbol("executeAsync");
return class {
/**
* 把任务推入宏队列
* @param handler 回调函数
* @param arg 传递给回调函数的参数
*/
[executeAsync] (handler, ...arg) {
setTimeout(function () {
handler(...arg);
}, 0)
}
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue promise新的数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
......
executeQueue.forEach((handler) => {
// 异步执行then中注册的回调
this[executeAsync] (handler, newValue);
})
}
constructor(executor) {
......
}
}
})();
然后我们在构造器中创建resolve和reject两个函数,传入executor即可
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}
这样使用时就可以接收到resolve和reject这两个函数,然后调用他们时,就可以改变promise的状态,然后就可以执行then中注册到回调列表中的函数了。
当然我们还需要做一点小收尾,因为如果传入的executor函数报错,会调用这个promise的reject方法,并把错误信息传入,所以我们需要加一个try catch
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
try {
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}catch (e) {
// 如果捕获到异常就调用reject
reject(e);
}
}
然后看看我们现在已经写好的所有的代码
const MyPromise = (function () {
// 对应的三个状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// 当前promise的数据
const PromiseValue = Symbol("PromiseValue");
// 当前promise的状态
const PromiseStatus = Symbol("PromiseStatus");
// 成功时要执行的回调函数列表
const onFulfilledList = Symbol("onFulfilledList");
// 失败时要执行的回调函数列表
const onRejectedList = Symbol("onRejectedList");
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
// 把任务添加到宏任务队列里的函数
const executeAsync = Symbol("executeAsync");
return class {
/**
* 把任务推入宏队列
* @param handler 回调函数
* @param arg 传递给回调函数的参数
*/
[executeAsync] (handler, ...arg) {
setTimeout(function () {
handler(...arg);
}, 0)
}
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue promise新的数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
// 如果状态不是pending, 就返回
if (this[PromiseStatus] !== PENDING) return;
// 把当前promise的状态改成新的状态
this[PromiseStatus] = newStatus;
// 把当前promise的值更新为新的值
this[PromiseValue] = newValue;
// 把回调列表里的函数取出来依次执行
executeQueue.forEach((handler) => {
// 异步执行then中注册的回调
this[executeAsync] (handler, newValue);
})
}
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
try {
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}catch (e) {
// 如果捕获到异常就调用reject
reject(e);
}
}
}
})();
测试一下
let promise = new MyPromise((resolve, reject) => {
resolve("sena");
});
自然是没有反应的,因为没有then,没有注册回调函数,自然什么也不会发生
实现then
实现then也不难,根据规范,我们需要返回一个promise,因为返回的新promise和现有的promise需要关联,这里我们用一个新的工具函数来创建这个promise
const MyPromise = (function () {
......
// 创建串联的promise
const createLinkPromise = Symbol("createLinkPromise");
return class {
......
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
});
}
then(onFulfilled, onRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
constructor(executor) {
......
}
}
})();
这里我们使用了一个新的工具函数[createLinkPromise],用于返回一个新的promise,在这里我们会对then的绑定的回调函数进行处理。
实现单个then的绑定事件
then如果传入了回调函数,首先会判断当前promise的状态,如果已经是resolve或者reject状态,就把回调函数推入微任务队列中异步执行,如果还是pending状态,就把回调函数放到promise的回调函数列表中,等状态改变了再执行,大概思路就是这样,我们现在来实现一下。
因为判断状态,立即执行,加入队列都可以抽象,所以我们用一个工具函数来完成这个过程
const MyPromise = (function () {
......
// 处理then中传入的回调
const settleHandle = Symbol("settleHandle");
return class {
......
/**
* 处理then传入的回调函数
* @param handler 回调函数
* @param immediatelyStatus 立即推入任务队列执行的状态
* @param queue 如果不立即执行,保存的队列
*/
[settleHandle] (handler, immediatelyStatus, queue) {
// 如果传入的不是一个函数就返回
if (typeof handler !== "function") return;
// 判断是不是立刻执行的状态
if (this[PromiseStatus] === immediatelyStatus) {
// 是就立刻推入异步执行队列
this[executeAsync] (handler, this[PromiseValue]);
} else {
// 不是就放到回调列表中
queue.push(handler);
}
}
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就处理then传入的回调了
this[settleHandle](resolve, RESOLVED, this[onFulfilledList]);
this[settleHandle](reject, REJECTED, this[onRejectedList]);
});
}
then(onFulfilled, onRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
constructor(executor) {
......
}
}
})();
[settleHandle]就是用来处理回调函数的工具函数。
好了,现在我们可以给promise通过then注册回调了,来看看完整的代码吧
const MyPromise = (function () {
// 对应的三个状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// 当前promise的数据
const PromiseValue = Symbol("PromiseValue");
// 当前promise的状态
const PromiseStatus = Symbol("PromiseStatus");
// 成功时要执行的回调函数列表
const onFulfilledList = Symbol("onFulfilledList");
// 失败时要执行的回调函数列表
const onRejectedList = Symbol("onRejectedList");
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
// 把回调函数添加到任务队列里异步执行的函数
const executeAsync = Symbol("executeAsync");
// 创建串联的promise
const createLinkPromise = Symbol("createLinkPromise");
// 后续处理的通用函数
const settleHandle = Symbol("settleHandle");
return class {
/**
* 让回调函数异步执行
* @param handler 回调函数
* @param arg 传递给回调函数的参数
*/
[executeAsync] (handler, ...arg) {
setTimeout(function () {
handler(...arg);
}, 0)
}
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue promise新的数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
// 如果状态不是pending, 就返回
if (this[PromiseStatus] !== PENDING) return;
// 把当前promise的状态改成新的状态
this[PromiseStatus] = newStatus;
// 把当前promise的值更新为新的值
this[PromiseValue] = newValue;
// 把回调列表里的函数取出来依次执行
executeQueue.forEach((handler) => {
// 异步执行then中注册的回调
this[executeAsync] (handler, newValue);
})
}
/**
* 处理then传入的回调函数
* @param handler 回调函数
* @param immediatelyStatus 立即推入任务队列执行的状态
* @param queue 如果不立即执行,保存的队列
*/
[settleHandle] (handler, immediatelyStatus, queue) {
// 如果传入的不是一个函数就返回
if (typeof handler !== "function") return;
// 判断是不是立刻执行的状态
if (this[PromiseStatus] === immediatelyStatus) {
// 是就立刻推入异步执行队列
this[executeAsync] (handler, this[PromiseValue]);
} else {
// 不是就放到回调列表中
queue.push(handler);
}
}
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就处理then传入的回调了
this[settleHandle](onFulfilled, RESOLVED, this[onFulfilledList]);
this[settleHandle](onRejected, REJECTED, this[onRejectedList]);
});
}
then(onFulfilled, onRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
try {
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}catch (e) {
// 如果捕获到异常就调用reject
reject(e);
}
}
}
})();
测试一下
let promise = new MyPromise((resolve, reject) => {
setTimeout(function () {
resolve("sena");
}, 1000);
console.log("123"); // 输出123
});
promise.then(function (data) {
console.log(1, data); // 1s后输出1 "sena"
});
promise.then(function (data) {
console.log(2, data); // 1s后输出2 "sena"
});
promise.then(function (data) {
console.log(3, data); // 1s后输出3 "sena"
});
实现then的链式调用
因为then已经返回了一个promise,所以我们要做的事情比较简单,就是处理一下回调函数的返回值和处理回调函数抛出的error就就行了,我们先处理返回值,返回值有两种情况
下文的的下一个Promise代指[createLinkPromise]返回的promise
- 返回非promise,直接把返回值通过调用resolve()传给下一个promise,下一个promise把这个返回值传给then注册的回调函数,就实现了前一个then的返回值作为下个then的参数
- 返回promise,给返回的promise用then注册成功和失败的回调,在两个回调中分别调用能修改下一个promise的状态的resolve和reject方法,从而完成数据的传递和延时执行
我们看看之前写的代码
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就处理then传入的回调了
this[settleHandle](onFulfilled, RESOLVED, this[onFulfilledList]);
this[settleHandle](onRejected, REJECTED, this[onRejectedList]);
});
}
[settleHandle] (handler, immediatelyStatus, queue) {
// 如果传入的不是一个函数就返回
if (typeof handler !== "function") return;
// 判断是不是立刻执行的状态
if (this[PromiseStatus] === immediatelyStatus) {
// 是就立刻推入异步执行队列
this[executeAsync] (handler, this[PromiseValue]);
} else {
// 不是就放到回调列表中
queue.push(handler);
}
}
很明显,因为我们不知道当前promise的状态,所以我们不知道传入的回调函数声明时候执行,所以要接收返回值,就要做一些特殊处理。
处理的方法也很简单,在回调函数的外面包一层,在外层函数里接收回调函数的返回值就行了
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就能处理then传入的回调了
// 在外面套一层
this[settleHandle]((data) => {
// 在这里就可以接收返回值,对返回值进行处理
let result = onFulfilled(data);
// 把返回值传给下个promise
resolve(result);
}, RESOLVED, this[onFulfilledList]);
this[settleHandle]((err) => {
let result = onRejected(err);
resolve(result);
}, REJECTED, this[onRejectedList]);
});
}
根据规范,如果then传入的onFulfilled函数执行时抛出了错误,就会调用reject函数,所以我们加个try catch在外面,由因为加try catch是重复的逻辑,所以我们可以再抽成一个工具函数[execute]。修改后的代码是这样的
const MyPromise = (function () {
......
// 执行then绑定的回调, 同时try catch
const execute = Symbol("execute");
return class {
......
/**
* 执行回调,获取返回值,如果报错就执行reject
* @param data 传给handler的数据
* @param handler 要在try catch中执行的回调函数
* @param resolve 下个promise的resolve
* @param reject 下个promise的reject
*/
[execute] (data, handler, resolve, reject) {
try {
const result = handler(data);
resolve(result);
}catch (e) {
reject(e);
}
}
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就处理then传入的回调了
this[settleHandle]((data) => {
this[execute](data, onFulfilled, resolve, reject);
}, RESOLVED, this[onFulfilledList]);
this[settleHandle]((err) => {
this[execute](err, onRejected, resolve, reject);
}, REJECTED, this[onRejectedList]);
});
}
constructor(executor) {
......
}
}
})();
现在的代码是这样的
const MyPromise = (function () {
// 对应的三个状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// 当前promise的数据
const PromiseValue = Symbol("PromiseValue");
// 当前promise的状态
const PromiseStatus = Symbol("PromiseStatus");
// 成功时要执行的回调函数列表
const onFulfilledList = Symbol("onFulfilledList");
// 失败时要执行的回调函数列表
const onRejectedList = Symbol("onRejectedList");
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
// 把任务添加到任务队列里异步执行的函数
const executeAsync = Symbol("executeAsync");
// 创建串联的promise
const createLinkPromise = Symbol("createLinkPromise");
// 后续处理的通用函数
const settleHandle = Symbol("settleHandle");
// 执行then绑定的回调, 同时try catch
const execute = Symbol("execute");
return class {
/**
* 异步执行回调函数
* @param handler 回调函数
* @param arg 传递给回调函数的参数
*/
[executeAsync] (handler, ...arg) {
setTimeout(function () {
handler(...arg);
}, 0)
}
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue promise新的数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
// 如果状态不是pending, 就返回
if (this[PromiseStatus] !== PENDING) return;
// 把当前promise的状态改成新的状态
this[PromiseStatus] = newStatus;
// 把当前promise的值更新为新的值
this[PromiseValue] = newValue;
// 把回调列表里的函数取出来依次执行
executeQueue.forEach((handler) => {
// 异步执行then中注册的回调
this[executeAsync] (handler, newValue);
})
}
/**
* 处理then传入的回调函数
* @param handler 回调函数
* @param immediatelyStatus 立即推入任务队列执行的状态
* @param queue 如果不立即执行,保存的队列
*/
[settleHandle] (handler, immediatelyStatus, queue) {
// 如果传入的不是一个函数就返回
if (typeof handler !== "function") return;
// 判断是不是立刻执行的状态
if (this[PromiseStatus] === immediatelyStatus) {
// 是就立刻推入异步执行队列
this[executeAsync] (handler, this[PromiseValue]);
} else {
// 不是就放到回调列表中
queue.push(handler);
}
}
/**
* 执行回调,获取返回值,如果报错就执行reject
* @param data 传给handler的数据
* @param handler 要在try catch中执行的回调函数
* @param resolve 下个promise的resolve
* @param reject 下个promise的reject
*/
[execute] (data, handler, resolve, reject) {
try {
const result = handler(data);
// 如果返回值是promise
if (result instanceof MyPromise) {
// 用then注册回调
result.then((data) => {
// 把回调收到的数据转发给下个promise
resolve(data);
}, (err) => {
reject(err);
})
}else {
// 如果返回值不是promise,直接传递就行
resolve(result);
}
}catch (e) {
reject(e);
}
}
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就能处理then传入的回调了
this[settleHandle]((data) => {
this[execute](data, onFulfilled, resolve, reject);
}, RESOLVED, this[onFulfilledList]);
this[settleHandle]((err) => {
this[execute](err, onRejected, resolve, reject);
}, REJECTED, this[onRejectedList]);
});
}
then(onFulfilled, onRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
try {
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}catch (e) {
// 如果捕获到异常就调用reject
reject(e);
}
}
}
})();
好了,现在我们已经处理完了返回值不是promise的情况,让我们测试一下
let promise = new MyPromise((resolve, reject) => {
setTimeout(function () {
resolve(1);
}, 1000);
}).then(function (data) {
console.log(data); // 1s后输出1
return data + 1;
}).then(function (data) {
console.log(data); // 1s后输出2
return data + 1;
}).then(function (data) {
console.log(data); // 1s后输出3
return data + 1;
});
现在我们来处理返回值是promise的情况,处理的方法原理也不难,给返回的promise注册回调,然后在回调里修改下一个promise的状态就行了
PS:下一个promise指的是[createLinkPromise]返回的promise
这里直接修改[execute]函数就行了
/**
* 执行回调,获取返回值,如果报错就执行reject
* @param data 传给handler的数据
* @param handler 要在try catch中执行的回调函数
* @param resolve 下个promise的resolve
* @param reject 下个promise的reject
*/
[execute] (data, handler, resolve, reject) {
try {
const result = handler(data);
// 如果返回值是promise
if (result instanceof MyPromise) {
// 用then注册回调
result.then((data) => {
// 把回调收到的数据转发给下个promise
resolve(data);
}, (err) => {
reject(err);
})
}else {
// 如果返回值不是promise,直接传递就行
resolve(result);
}
}catch (e) {
reject(e);
}
}
好了,返回值是promise的情况也处理好了,来测试一下
let promise = new MyPromise((resolve, reject) => {
setTimeout(function () {
resolve("sena");
}, 1000);
console.log("sion");
}).then((data) => {
console.log("1",data);
return data;
}).then((data) => {
console.log("2",data);
return new MyPromise((resolve) => {
setTimeout(() => {
resolve("sakura");
}, 2000)
});
}).then((data) => {
console.log("3",data);
return data;
});
console.log("yyy");
输出情况,看起来是正常的
// sion
// yyy
// 1s后输出: 1 sena
// 1s后输出: 2 sena
// 2s后输出: 3 sakura
其实到这里,一个promise大致就完成了,接下来就是一些细节处理了
处理空then
如果中间的某个then没有传入回调,虽然我没在规范中找到这种情况(可能是我看漏了),但是在我测试官方promise时回调函数的执行不会中断,所以我们要做些处理
处理的方法也比较简单,如果onFulfilled, onRejected没有传入,使用默认的onFulfilled, onRejected函数,把数据转发就行了
const MyPromise = (function () {
......
// 默认的OnFulfilled
const defaultOnFulfilled = function (data) {return data};
// 默认的OnRejected
const defaultOnRejected = function (err) {throw new Error(err)};
return class {
// 给onFulfilled, onRejected 默认值
then(onFulfilled = defaultOnFulfilled, onRejected = defaultOnRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
constructor(executor) {
......
}
}
})();
测试代码
let promise = new MyPromise((resolve, reject) => {
setTimeout(function () {
resolve("sena");
}, 1000);
console.log("sion");
}).then((data) => {
console.log("1",data);
return data;
}).then((data) => {
console.log("2",data);
return new MyPromise((resolve) => {
setTimeout(() => {
resolve("sakura");
}, 1000)
});
}).then().then((data) => {
console.log("3",data);
return data;
});
console.log("yyy");
输出情况
// sion
// yyy
// 1s后输出: 1 sena
// 1s后输出: 2 sena
// 2s后输出: 3 sakura 如果没有处理空then,不会出现这个
完善promise的其他函数
catch和finally函数
catch其实是特殊的then函数,简单来说就是没有onFulfilled的then函数。
finally也是特殊的then函数,就是无论什么状态都执行相同的回调
所以可以直接调用then来实现
catch(onRejected) {
return this.then(defaultOnFulfilled, onRejected);
}
finally(handler) {
return this.then(handler, handler);
}
all函数
all函数接收一个promise数组,返回一个promise,只有传入的数据中的所有promise都处于resolved状态后,返回的promise才会处于resolved状态,有任何一个promise处于reject状态后,返回的promise就会处于reject状态
static all(promises) {
// promise数组的长度
let length = promises.length;
// 创建用于保存结果的数组
let resultArr = new Array(length);
// 已经处于resolved状态的promise的个数
let count = 0;
return new MyPromise((resolve, reject) => {
promises.map((promise, index) => {
// 给每个promise都注册回调
promise.then((data) => {
// 处于resolve状态后, 把count加1
count ++;
// 保存数据到数组中
resultArr[index] = data;
// 如果全部处于resolved状态
if (count >= length) {
// 就把返回的promise变成resolved状态
resolve(resultArr);
}
}, (err) => {
// 有任一个处于rejected状态
// 就把返回的promise置为rejected状态
reject(err);
})
})
})
}
race函数
race函数接收一个promise数组,返回一个promise,返回的promise的状态会与promise数组中的第一个修改状态的项同步修改成相同的值
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
// 任意一个修改状态后就修改返回的promise的状态
promise.then((data) => {
resolve(data);
}, (err) => {
reject(err);
})
})
});
}
resolve函数
resolve函数返回一个已经处于resolved状态的promise,接收要传给回调函数的data
static resolve(data) {
if (data instanceof MyPromise) return data;
return new MyPromise((resolve) => {
resolve(data);
})
}
reject函数
reject函数返回一个已经处于reject状态的promise,接收要传给回调函数的data
static reject(err) {
if (data instanceof MyPromise) return err;
return new MyPromise((resolve, reject) => {
reject(err);
})
}
好了,到这里所有的代码就暂时实现完了,当然我后期会再加些方法上去,不过那是以后的事了,最后放一波完整的代码
const MyPromise = (function () {
// 对应的三个状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// 当前promise的数据
const PromiseValue = Symbol("PromiseValue");
// 当前promise的状态
const PromiseStatus = Symbol("PromiseStatus");
// 成功时要执行的回调函数列表
const onFulfilledList = Symbol("onFulfilledList");
// 失败时要执行的回调函数列表
const onRejectedList = Symbol("onRejectedList");
// 更新状态的函数
const updateStatus = Symbol("updateStatus");
// 把任务添加到任务队列里异步执行的函数
const executeAsync = Symbol("executeAsync");
// 创建串联的promise
const createLinkPromise = Symbol("createLinkPromise");
// 后续处理的通用函数
const settleHandle = Symbol("settleHandle");
// 执行then绑定的回调, 同时try catch
const execute = Symbol("execute");
// 默认的OnFulfilled
const defaultOnFulfilled = function (data) {return data};
// 默认的OnRejected
const defaultOnRejected = function (err) {throw new Error(err)};
return class {
/**
* 异步执行回调函数
* @param handler 回调函数
* @param arg 传递给回调函数的参数
*/
[executeAsync] (handler, ...arg) {
setTimeout(function () {
handler(...arg);
}, 0)
}
/**
* 更新状态
* @param newStatus 新的状态
* @param newValue promise新的数据
* @param executeQueue 要执行的回调列表
*/
[updateStatus] (newStatus, newValue, executeQueue) {
// 如果状态不是pending, 就返回
if (this[PromiseStatus] !== PENDING) return;
// 把当前promise的状态改成新的状态
this[PromiseStatus] = newStatus;
// 把当前promise的值更新为新的值
this[PromiseValue] = newValue;
// 把回调列表里的函数取出来依次执行
executeQueue.forEach((handler) => {
// 异步执行then中注册的回调
this[executeAsync] (handler, newValue);
})
}
/**
* 处理then传入的回调函数
* @param handler 回调函数
* @param immediatelyStatus 立即推入任务队列执行的状态
* @param queue 如果不立即执行,保存的队列
*/
[settleHandle] (handler, immediatelyStatus, queue) {
// 如果传入的不是一个函数就返回
if (typeof handler !== "function") return;
// 判断是不是立刻执行的状态
if (this[PromiseStatus] === immediatelyStatus) {
// 是就立刻推入异步执行队列
this[executeAsync] (handler, this[PromiseValue]);
} else {
// 不是就放到回调列表中
queue.push(handler);
}
}
/**
* 执行回调,获取返回值,如果报错就执行reject
* @param data 传给handler的数据
* @param handler 要在try catch中执行的回调函数
* @param resolve 下个promise的resolve
* @param reject 下个promise的reject
*/
[execute] (data, handler, resolve, reject) {
try {
const result = handler(data);
// 如果返回值是promise
if (result instanceof MyPromise) {
// 用then注册回调
result.then((data) => {
// 把回调收到的数据转发给下个promise
resolve(data);
}, (err) => {
reject(err);
})
}else {
// 如果返回值不是promise,直接传递就行
resolve(result);
}
}catch (e) {
reject(e);
}
}
/**
* 用于创建then返回的新promise
* @param onFulfilled then里传入的onFulfilled函数
* @param onRejected then里传入的onRejected函数
*/
[createLinkPromise] (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 在这里调用[settleHandle]就能处理then传入的回调了
this[settleHandle]((data) => {
this[execute](data, onFulfilled, resolve, reject);
}, RESOLVED, this[onFulfilledList]);
this[settleHandle]((err) => {
this[execute](err, onRejected, resolve, reject);
}, REJECTED, this[onRejectedList]);
});
}
then(onFulfilled = defaultOnFulfilled, onRejected = defaultOnRejected) {
return this[createLinkPromise](onFulfilled, onRejected);
}
catch(onRejected) {
return this.then(defaultOnFulfilled, onRejected);
}
finally(handler) {
return this.then(handler, handler);
}
constructor(executor) {
this[PromiseStatus] = PENDING;
this[PromiseValue] = undefined;
this[onFulfilledList] = [];
this[onRejectedList] = [];
// 定义resolve函数
const resolve = (data) => {
this[updateStatus](RESOLVED, data, this[onFulfilledList]);
};
// 定义reject函数
const reject = (reason) => {
this[updateStatus](REJECTED, reason, this[onRejectedList]);
};
try {
// 同步执行new Promise时传入的函数
executor && executor(resolve, reject);
}catch (e) {
// 如果捕获到异常就调用reject
reject(e);
}
}
static all(promises) {
// promise数组的长度
let length = promises.length;
// 创建用于保存结果的数组
let resultArr = new Array(length);
// 已经处于resolved状态的promise的个数
let count = 0;
return new MyPromise((resolve, reject) => {
promises.map((promise, index) => {
// 给每个promise都注册回调
promise.then((data) => {
// 处于resolve状态后, 把count加1
count ++;
// 保存数据到数组中
resultArr[index] = data;
// 如果全部处于resolved状态
if (count >= length) {
// 就把返回的promise变成resolved状态
resolve(resultArr);
}
}, (err) => {
// 有任一个处于rejected状态
// 就把返回的promise置为rejected状态
reject(err);
})
})
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
// 任意一个修改状态后就修改返回的promise的状态
promise.then((data) => {
resolve(data);
}, (err) => {
reject(err);
})
})
});
}
static resolve(data) {
if (data instanceof MyPromise) return data;
return new MyPromise((resolve) => {
resolve(data);
})
}
static reject(err) {
if (data instanceof MyPromise) return err;
return new MyPromise((resolve, reject) => {
reject(err);
})
}
}
})();
感谢你的阅读