写了一年的Promise
,今天终于是把测试跑通了,其它都不是难点,难点在于resolvePromise
,这是所有里面最难的,当然我们抛开这个先不谈,先实现一些基本的特性.
1. Promise 的三个基本属性
Promise有三个基本属性
- value:
Promise
成功的值 - reason:
Promise
失败的理由 - state:状态,有
pending
,fulfilled
,rejected
状态
所以我们可以添加三个属性值,以及关于State
的三个状态的常量:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value; // 成功的值
reason; // 失败的理由
state = State.pending;
}
2. Promise 的构造器
Promise
的构造器传入参数是一个函数
,并传入resolve
和reject
函数,用来改变Promise
对象的状态,所以我们可以得到如下代码:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value;
reason;
state = State.pending;
constructor(exector){
exector?.(this.resolve.bind(this), this.reject.bind(this)); // 新增的代码
}
resolve(){} // 新增的代码
reject(){} // 新增的代码
}
2. resolve和reject
在Promise
中调用这两
个函数,分别会将Promise
的状态改为fulfilled
和rejected
,所以加入状态的改变:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value;
reason;
state = State.pending;
constructor(exector){
exector?.(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value){
this.value = value; // 新增的代码
this.state = State.fulfilled; // 新增的代码
}
reject(reason){
this.reason = reason; // 新增的代码
this.state = State.rejected; // 新增的代码
}
}
当然,Promise
在状态修改
后,就不能再次修改
,所以我们加入判断
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value;
reason;
state = State.pending;
constructor(exector){
exector?.(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value){
if (this.state !== State.pending) return; // 新增的代码
this.value = value;
this.state = State.fulfilled;
}
reject(reason){
if (this.state !== State.pending) return; // 新增的代码
this.reason = reason;
this.state = State.rejected;
}
}
3. then
函数
then
函数返回一个新的Promise
对象,参数是两个函数
,第一个函数
是前一个promise
对象被Resolve
时调用,第二个函数
是前一个对象被Reject
时调用,所以我们加上一个then
方法,并返回一个新的Promise
,并且调用它的Resolve
和Reject
:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value;
reason;
state = State.pending;
constructor(exector){
exector?.(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value){
if (this.state !== State.pending) return;
this.value = value;
this.state = State.fulfilled;
}
reject(reason){
if (this.state !== State.pending) return;
this.reason = reason;
this.state = State.rejected;
}
// 新增代码
then(onFulfilled, onRejected) {
let onFulfilledFn;
let onRejectedFn;
const nextPromise = new MyPromise((resolve, reject) => {
onFulfilledFn = function () {
const result = onFulfilled(this.value)
resolve(result);
};
onRejectedFn = function () {
const result = onRejected(this.reason);
resolve(result);
};
});
onFulfilledFn = onFulfilledFn.bind(this);
onRejectedFn = onRejectedFn.bind(this);
if (this.state === State.fulfilled) {
onFulfilledFn();
} else if (this.state === State.rejected) {
onRejectedFn();
}
return nextPromise;
}
}
promise对象
被resolve
或者reject
的时候,then
函数不是立即执行的,也就是说是异步的
,所以,我们需要在回调外面套上queueMircrotask
:
... 省略
then(onFulfilled, onRejected) {
let onFulfilledFn;
let onRejectedFn;
const nextPromise = new MyPromise((resolve, reject) => {
onFulfilledFn = function () {
queueMicrotask(()=>{
const result = onFulfilled(this.value)
resolve(result);
});
};
onRejectedFn = function () {
queueMircotask(()=>{
const result = onRejected(this.reason);
resolve(result);
})
};
});
onFulfilledFn = onFulfilledFn.bind(this);
onRejectedFn = onRejectedFn.bind(this);
if (this.state === State.fulfilled) {
onFulfilledFn();
} else if (this.state === State.rejected) {
onRejectedFn();
}
return nextPromise;
}
... 省略
但是此时我们执行这个例子
new MyPromise((resolve)=>{ setTimeout(()=>{ resolve(1) }) })
.then((res)=>{console.log(res)})
你会发现没有任何输出
这是因为刚才的then
只能同步执行
:
所以我们需要用数组来保存订阅
,并在状态发生变更
的时候执行数组
中的函数:
...省略
class MyPromise {
...省略
onFulfilledFnArray = [];
onRejectedFnArray = []; // 为了可以 let a = Promise; a.then(); a.then()}
...省略
}
...省略
then变更为
:
...省略
then(onFulfilled, onRejected) {
let onFulfilledFn;
let onRejectedFn;
const nextPromise = new MyPromise((resolve, reject) => {
onFulfilledFn = function () {
queueMicrotask(()=>{
const result = onFulfilled(this.value)
resolve(result);
});
};
onRejectedFn = function () {
queueMircotask(()=>{
const result = onRejected(this.reason);
resolve(result);
})
};
});
onFulfilledFn = onFulfilledFn.bind(this);
onRejectedFn = onRejectedFn.bind(this);
if (this.state === State.fulfilled) {
onFulfilledFn();
} else if (this.state === State.rejected) {
onRejectedFn();
} else {
// 新增代码
this.onFulfilledFnArray.push(onFulfilledFn);
this.onRejectedFnArray.push(onRejectedFn);
}
return nextPromise;
}
...省略
修改一下resolve
和reject
:
...省略
class MyPromise {
...省略
resolve(value) {
if (this.state !== State.pending) return;
this.value = value;
this.state = State.fulfilled;
// 新增代码
while (this.onFulfilledFnArray.length > 0) {
this.onFulfilledFnArray.shift()(); // 不是立即执行
}
}
reject(reason) {
if (this.state !== State.pending) return;
this.reason = reason;
this.state = State.rejected;
// 新增代码
while (this.onRejectedFnArray.length > 0) {
this.onRejectedFnArray.shift()(); // 不是立即执行
}
}
...省略
}
...省略
给出当前的完整代码:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value;
reason;
onFulfilledFnArray = [];
onRejectedFnArray = [];
state = State.pending;
constructor(exector){
exector?.(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state !== State.pending) return;
this.value = value;
this.state = State.fulfilled;
// 新增代码
while (this.onFulfilledFnArray.length > 0) {
this.onFulfilledFnArray.shift()(); // 不是立即执行
}
}
reject(reason) {
if (this.state !== State.pending) return;
this.reason = reason;
this.state = State.rejected;
// 新增代码
while (this.onRejectedFnArray.length > 0) {
this.onRejectedFnArray.shift()(); // 不是立即执行
}
}
then(onFulfilled, onRejected) {
let onFulfilledFn;
let onRejectedFn;
const nextPromise = new MyPromise((resolve, reject) => {
onFulfilledFn = function () {
queueMicrotask(()=>{
const result = onFulfilled(this.value)
resolve(result);
});
};
onRejectedFn = function () {
queueMircotask(()=>{
const result = onRejected(this.reason);
resolve(result);
})
};
});
onFulfilledFn = onFulfilledFn.bind(this);
onRejectedFn = onRejectedFn.bind(this);
if (this.state === State.fulfilled) {
onFulfilledFn();
} else if (this.state === State.rejected) {
onRejectedFn();
} else {
// 新增代码
this.onFulfilledFnArray.push(onFulfilledFn);
this.onRejectedFnArray.push(onRejectedFn);
}
return nextPromise;
}
}
可以发现成功输出1
4. resolve传递值的规则
resolve
不能传递同一个Promise
对象,否则会报错
这种情况一般发生在异步代码中:
const promise = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(promise)
})
})
Promise – JavaScript | MDN (mozilla.org)
所以我们需要写一个resolvePromise
的函数,来过滤掉特殊情况
resolvePromise(value) {
if (value === this) {
this.reject(
new TypeError(
'Circular reference detected: promise and x are the same object',
),
);
return false;
}
}
thenable
对象
当遇到thenable
对象时,会调用thenable
对象的then
,并将resolve
的值作为promise
的最终状态。
resolvePromise(value) {
let called = false;
if (value === this) {
// 省略
} else if (value instanceof MyPromise) {
try {
value.then(
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
} else if (value && typeof value === 'object') {
try {
const thenable = Reflect.get(value, 'then');
if (typeof thenable === 'function') {
try {
thenable.call(
value,
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
} else if (value && typeof value === 'function') {
try {
if (Reflect.has(value, 'then')) {
return this.resolvePromise(Reflect.get(value, 'then'));
}
if (value) {
try {
value.call(
value,
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
return true;
}
最后修改一下resolve
函数:
resolve(value) {
if (this.state !== State.pending) return;
if (!this.resolvePromise(value)) return; // 特殊对象,特殊解析
this.value = value;
this.state = State.fulfilled;
while (this.onFulfilledFnArray.length > 0) {
this.onFulfilledFnArray.shift()(); // 不是立即执行
}
}
还没想好怎么写,正在施工
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
先给出完整代码:
const State = {
pending: 'pending',
fulfilled: 'fulfilled',
rejected: 'rejected',
};
class MyPromise {
value; // 成功的值
reason; // 失败的理由
state = State.pending;
onFulfilledFnArray = [];
onRejectedFnArray = []; // 为了可以 let a = Promise; a.then(); a.then()
constructor(exector) {
exector?.(this.resolve.bind(this), this.reject.bind(this));
}
static resolve(value) {
return new MyPromise(resolve => {
resolve(value);
});
}
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(value);
});
}
resolvePromise(value) {
let called = false;
if (value === this) {
this.reject(
new TypeError(
'Circular reference detected: promise and x are the same object',
),
);
return false;
} else if (value instanceof MyPromise) {
try {
value.then(
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
} else if (value && typeof value === 'object') {
try {
const thenable = Reflect.get(value, 'then');
if (typeof thenable === 'function') {
try {
thenable.call(
value,
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
} else if (value && typeof value === 'function') {
try {
if (Reflect.has(value, 'then')) {
return this.resolvePromise(Reflect.get(value, 'then'));
}
if (value) {
try {
value.call(
value,
x => {
if (called) return;
called = true;
this.resolve(x);
},
y => {
if (called) return;
called = true;
this.reject(y);
},
);
return false;
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
} catch (e) {
if (called) return;
this.reject(e);
return false;
}
}
return true;
}
resolve(value) {
if (this.state !== State.pending) return;
if (!this.resolvePromise(value)) return;
this.value = value;
this.state = State.fulfilled;
while (this.onFulfilledFnArray.length > 0) {
this.onFulfilledFnArray.shift()(); // 不是立即执行
}
}
reject(reason) {
if (this.state !== State.pending) return;
this.reason = reason;
this.state = State.rejected;
while (this.onRejectedFnArray.length > 0) {
this.onRejectedFnArray.shift()(); // 不是立即执行
}
}
catch(onFulfilled) {
return this.then(undefined, onFulfilled);
}
then(onFulfilled, onRejected) {
let onFulfilledFn;
let onRejectedFn;
const nextPromise = new MyPromise((resolve, reject) => {
onFulfilledFn = function () {
queueMicrotask(() => {
try {
if (typeof onFulfilled === 'function') {
const result = onFulfilled(this.value);
resolve(result);
} else {
resolve(this.value);
}
} catch (e) {
reject(e);
}
});
};
onRejectedFn = function () {
queueMicrotask(() => {
try {
if (onRejected) {
if (typeof onRejected === 'function') {
const result = onRejected(this.reason);
resolve(result);
} else {
reject(this.reason);
}
} else {
reject(this.reason);
}
} catch (e) {
reject(e);
}
});
};
});
onFulfilledFn = onFulfilledFn.bind(this);
onRejectedFn = onRejectedFn.bind(this);
if (this.state === State.fulfilled) {
onFulfilledFn();
} else if (this.state === State.rejected) {
onRejectedFn();
} else {
this.onFulfilledFnArray.push(onFulfilledFn);
this.onRejectedFnArray.push(onRejectedFn);
}
return nextPromise;
}
}
代码仓库以及测试:
javascript/面试题/手写Promise/index.js at master · RadiumAg/javascript (github.com)
原文链接:https://juejin.cn/post/7357735854716895244 作者:RadiumAg