手写一个 Promise
手写一个 Promise 首先要了解以下几点
- Promise 是一个类,在执行这个类的时候需要传递一个执行器,执行器会立即执行
- Promise 中有三种状态分别为成功(fulfilled)失败(rejected)等待 (pending)。改变状态只能是 pending 变为 fulfilled 或 rejected,一旦状态确定就不可更改。
- resolve和reject函数是用来改变状态的。这两个函数会分别接收一个参数
- then方法内部做的事情就是判断状态,如果状态为成功,调用成功的回调函数,如果是失败则调用失败的回调函数。then方法是被定义在原型对象中的。
- then 成功回调有一个参数,表示 成功之后的值,失败回调也有一个参数,表示 失败后的原因
参考以上定义,开始动手。
// 定义状态常量
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失败
class MyPromise {
//executor 就是执行器
constructor(executor) {
executor(this.resolve, this.reject);
}
status = PENDING; // 默认为等待
value = undefined; // 成功之后的值
reason = undefined; // 失败后的原因
//这里要用箭头函数,避免this问题
resolve = (value) => {
//将状态变更为成功
if (this.set_status(FULFILLED)) {
// 保存成功值
this.value = value;
}
};
reject = (reason) => {
//将状态变更为失败
if (this.set_status(REJECTED)) {
// 保存失败原因
this.reason = reason;
}
};
set_status(status) {
//判断状态是否为等待 ,因为 Promise状态一旦状态确定就不可更改。
if (this.status === PENDING) {
this.status = status;
return true;
}
return false;
}
then(success_callback, fail_callback) {
// 判断状态
if (this.status === FULFILLED) {
success_callback(this.value); // 将成功值返回
} else if (this.status === REJECTED) {
fail_callback(this.reason); // 将失败原因返回
}
}
}
// 测试
const promise = new MyPromise((resolve, reject) => {
resolve("成功");
reject("失败");
});
promise.then(
(v) => {
console.log(v);
},
(err) => {
console.log(err);
}
);
// 打印 ‘成功’ ,因为状态不可再改变所以失败不会被打印。
以上只是一个基本的 Promise 的实现,但我们并没有考虑到异步情况,接下来我们解决一下异步的问题。
那么如何判断异步呢?首先在判断状态的时候如果为等待,我们就把两个回调函数保存起来,等resolve或者reject 被触发的时候在调用回调函数即可。
//注意:为了方便展示,此段代码仅保留了变更后的方法。
class MyPromise {
...
success_callback = undefined; // 成功回调
fail_callback = undefined; // 失败回调
resolve = (value) => {
if (this.set_status(FULFILLED)) {
this.value = value;
//判断成功回调是否存,如果存在就调用
if (this.success_callback) {
this.success_callback(value); // 传递成功值
}
}
};
reject = (reason) => {
if (this.set_status(REJECTED)) {
this.reason = reason;
//判断成功回调是否存,如果存在就调用
if (this.fail_callback) {
this.fail_callback(reason); // 传递失败原因
}
}
};
...
then(success_callback, fail_callback) {
if (this.status === FULFILLED) {
success_callback(this.value);
} else if (this.status === REJECTED) {
fail_callback(this.reason);
} else {
// 代码到此说明状态未发生改变。
// 所以我们暂时把两个回调存储起来
this.success_callback = success_callback;
this.fail_callback = fail_callback;
}
}
}
那么异步的的问题我们解决好了,但还是有一个问题。同一个promise对象的then方法是可以被多次调用的,当then方法被多次调用之后,每一个then方法中传递的回调函数都是要被执行的。那我们在处理下这个问题。
// 解决这个问题也很简单,只需要把存储的回调函数变成数组形式存储即可
success_callback = []; // 成功回调
fail_callback = []; // 失败回调
resolve = (value) => {
if (this.set_status(FULFILLED)) {
this.value = value;
while (this.success_callback.length) {
this.success_callback.shift()(value); // 传递成功值
}
}
};
reject = (reason) => {
if (this.set_status(REJECTED)) {
this.reason = reason;
while (this.fail_callback.length) {
this.fail_callback.shift()(value); // 传递失败原因
}
}
};
then(success_callback, fail_callback) {
if (this.status === FULFILLED) {
success_callback(this.value);
} else if (this.status === REJECTED) {
fail_callback(this.reason);
} else {
// push 到数组里
this.success_callback.push(success_callback);
this.fail_callback.push(fail_callback);
}
}
promise 的then方法是可以链式调用的,后面then方法拿到的值实际上是上一个then方法的返回值。
// 列如
promise.then((v) => {
console.log(v);
return 100;
},(err) => {
console.log(err);
}).then(v => {
console.log(v);
})
这个如何实现呢?我们要分成两个步骤来做,第一个要实现then的链式调用,第二就是如何把上一个then方法的返回值传递给后面的then。首相要清楚一点then是promise里的方法,如果我们想实现then方法的链式调用,那么每一个then方法它应该都返回一个promise对象。
then(success_callback, fail_callback) {
// 直接返回一个 新的 MyPromise 对象
return new MyPromise(() => {
if (this.status === FULFILLED) {
success_callback(this.value);
} else if (this.status === REJECTED) {
fail_callback(this.reason);
} else {
this.success_callback.push(success_callback);
this.fail_callback.push(fail_callback);
}
});
}
接下来在处理上一个then 返回回来的值,我们用一个单独的方法来处理
then(success_callback, fail_callback) {
const promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
const v = success_callback(this.value);
this.resolve_promise(v, resolve, reject);
} else if (this.status === REJECTED) {
fail_callback(this.reason);
} else {
this.success_callback.push(success_callback);
this.fail_callback.push(fail_callback);
}
});
return promise;
}
resolve_promise(v, resolve, reject) {
// 判断 v 是否是 MyPromise 对象,如果是 还要判断这个 MyPromise 的状态
if (v instanceof MyPromise) {
v.then(resolve, reject); // 如果是 MyPromise 它是什么状态 相应的我们就传递什么状态.
} else {
resolve(v);
}
}
then方法的链式调用其实还有一个判断需要处理一下的,就是返回的对象不能是当前的promise对象,不然就会触发循环调用。当然这个也非常好处理。
//我们只需要判断 success_callback 返回的值是否全等于 new 出的 promise 即可
resolve_promise(promise, v, resolve, reject) {
if (promise === v) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
...
}
}
到现在,我们还没有进行错误处理的,为了程序的健壮性,我们还是要去捕获错误并处理错误的。
//在执行器进行trycatch。如果出现错误调用reject并传递错误即可
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
//then方法里同样也需要在成功回调函数里捕获错误
then(success_callback, fail_callback) {
const promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 为了能在这里获取到 promise,讲一下代码变成异步
setTimeout(() => {
try {
const v = success_callback(this.value); // 将成功值返回
this.resolve_promise(promise, v, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
...
}
以上我们仅仅只处理了then 同步情况下成功的相关问题,我们封装下把其他的一起处理了。
...
class MyPromise {
//executor 就是执行器
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
status = PENDING; // 默认为等待
value = undefined; // 成功之后的值
reason = undefined; // 失败后的原因
success_callback = []; // 成功回调
fail_callback = []; // 失败回调
//这里要用箭头函数,避免this问题
resolve = (value) => {
//将状态变更为成功
if (this.set_status(FULFILLED)) {
// 保存成功值
this.value = value;
//判断成功回调是否存,如果存在就调用
while (this.success_callback.length) {
const fn = this.success_callback.shift();
fn();
}
}
};
reject = (reason) => {
//将状态变更为失败
if (this.set_status(REJECTED)) {
// 保存失败原因
this.reason = reason;
//判断成功回调是否存,如果存在就调用
while (this.fail_callback.length) {
const fn = this.fail_callback.shift();
fn();
}
}
};
set_status(status) {
//判断状态是否为等待 ,因为 Promise状态一旦状态确定就不可更改。
if (this.status === PENDING) {
this.status = status;
return true;
}
return false;
}
then(success_callback, fail_callback) {
success_callback = success_callback ? success_callback : (value) => value;
fail_callback = fail_callback ? fail_callback : (reason) => reason;
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
// 为了能在这里获取到 promise,讲一下代码变成异步
setTimeout(() => {
this.resolve_promise(
promise,
success_callback,
this.value,
resolve,
reject
);
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
this.resolve_promise(
promise,
fail_callback,
this.reason,
resolve,
reject
);
}, 0);
} else {
// 代码到此说明状态未发生改变。
// 所以我们暂时把两个回调存储起来
this.success_callback.push(() => {
setTimeout(() => {
this.resolve_promise(
promise,
success_callback,
this.value,
resolve,
reject
);
}, 0);
});
this.fail_callback.push(() => {
setTimeout(() => {
this.resolve_promise(
promise,
fail_callback,
this.reason,
resolve,
reject
);
}, 0);
});
}
});
return promise;
}
resolve_promise(promise, callback, value, resolve, reject) {
try {
const v = callback(value);
if (promise === v) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
// 判断 v 是否是 MyPromise 对象,如果是 还要判断这个 MyPromise 的状态
if (v instanceof MyPromise) {
v.then(resolve, reject); // 如果是 MyPromise 它是什么状态 相应的我们就传递什么状态.
} else {
resolve(v);
}
} catch (error) {
reject(error);
}
}
}
然后再把一些Promise其他方法补充一下。
// all 是通过 Promise点出来的所以 是个静态方法
static all(array) {
const result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
// all 的核心就是等待所有Promise都 resolve 的时候在调用自己的resolve
// 所以我们定义一个添加所有结果的函数。每次添加完毕的时候判断是否已经全部添加完成。然后就可以调用resolve
function add_data(key, value) {
result[key] = value;
index++;
if (index === array.length) {
reject(result);
}
}
for (let i = 0; i < array.length; i++) {
const current = array[i];
if (current instanceof MyPromise) {
// MyPromise 类型
current.then(
(value) => add_data(i, value),
(resolve) => reject(resolve)
);
} else {
// 普通值
add_data(i, current);
}
}
});
}
// resolve方法就相对简单一些
static resolve(value) {
if (value instanceof MyPromise) {
return value;
} else {
return new MyPromise((resolve) => resolve(value));
}
}
finally(callback) {
// 得到当前 状态,以及不管什么状态调用回调函数
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value); // 将结果向下传递
},
(reason) => {
return MyPromise.resolve(callback()).then(() => {
throw reason;
}); // 将错误原因向下传递
}
);
}
catch(fail_callback) {
return this.then(undefined, fail_callback);
}
最后是 最终代码
// 定义状态常量
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失败
class MyPromise {
//executor 就是执行器
constructor(executor) {
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
status = PENDING; // 默认为等待
value = undefined; // 成功之后的值
reason = undefined; // 失败后的原因
success_callback = []; // 成功回调
fail_callback = []; // 失败回调
//这里要用箭头函数,避免this问题
resolve = (value) => {
//将状态变更为成功
if (this.set_status(FULFILLED)) {
// 保存成功值
this.value = value;
//判断成功回调是否存,如果存在就调用
while (this.success_callback.length) {
const fn = this.success_callback.shift();
fn();
}
}
};
reject = (reason) => {
//将状态变更为失败
if (this.set_status(REJECTED)) {
// 保存失败原因
this.reason = reason;
//判断成功回调是否存,如果存在就调用
while (this.fail_callback.length) {
const fn = this.fail_callback.shift();
fn();
}
}
};
set_status(status) {
//判断状态是否为等待 ,因为 Promise状态一旦状态确定就不可更改。
if (this.status === PENDING) {
this.status = status;
return true;
}
return false;
}
then(success_callback, fail_callback) {
// 判断回调是否存在,不存在把值向下传递
success_callback = success_callback ? success_callback : (value) => value;
fail_callback = fail_callback ? fail_callback : (reason) => reason;
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
// 为了能在这里获取到 promise,讲一下代码变成异步
setTimeout(() => {
this.resolve_promise(
promise,
success_callback,
this.value,
resolve,
reject
);
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
this.resolve_promise(
promise,
fail_callback,
this.reason,
resolve,
reject
);
}, 0);
} else {
// 代码到此说明状态未发生改变。
// 所以我们暂时把两个回调存储起来
this.success_callback.push(() => {
setTimeout(() => {
this.resolve_promise(
promise,
success_callback,
this.value,
resolve,
reject
);
}, 0);
});
this.fail_callback.push(() => {
setTimeout(() => {
this.resolve_promise(
promise,
fail_callback,
this.reason,
resolve,
reject
);
}, 0);
});
}
});
return promise;
}
finally(callback) {
// 得到当前 状态,以及不管什么状态调用回调函数
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value); // 将结果向下传递
},
(reason) => {
return MyPromise.resolve(callback()).then(() => {
throw reason;
}); // 将错误原因向下传递
}
);
}
catch(fail_callback) {
return this.then(undefined, fail_callback);
}
resolve_promise(promise, callback, value, resolve, reject) {
try {
const v = callback(value);
if (promise === v) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
// 判断 v 是否是 MyPromise 对象,如果是 还要判断这个 MyPromise 的状态
if (v instanceof MyPromise) {
v.then(resolve, reject); // 如果是 MyPromise 它是什么状态 相应的我们就传递什么状态.
} else {
resolve(v);
}
} catch (error) {
reject(error);
}
}
// all 是通过 Promise点出来的所以 是个静态方法
static all(array) {
const result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
// all 的核心就是等待所有Promise都 resolve 的时候在调用自己的resolve
// 所以我们定义一个添加所有结果的函数。每次添加完毕的时候判断是否已经全部添加完成。然后就可以调用resolve
function add_data(key, value) {
result[key] = value;
index++;
if (index === array.length) {
reject(result);
}
}
for (let i = 0; i < array.length; i++) {
const current = array[i];
if (current instanceof MyPromise) {
// MyPromise 类型
current.then(
(value) => add_data(i, value),
(resolve) => reject(resolve)
);
} else {
// 普通值
add_data(i, current);
}
}
});
}
// resolve方法就相对简单一些
static resolve(value) {
if (value instanceof MyPromise) {
return value;
} else {
return new MyPromise((resolve) => resolve(value));
}
}
}
注:内容均来自互联网,若有侵权,请联系删除
评论
暂无评论