promise手写
promise基础规则
- Promise是一个构造函数
- Promise接受一个函数,同时这个函数接收两个参数 (resolve,reject),他们也是函数
- Promise返回的对象,包含一个then函数,then函数接收两个参数,一般他们也是函数
- 在使用new关键字调用 Promise 构造函数时,在结束的时候 如果正确执行,调用resolve方法,将结果放在resolve的参数中执行,这个结果可以在then中的第一个函数参数(onFulfilled)中拿到 如果错误执行,调用reject方法,将结果放在reject的参数中执行,这个结果可以在then中的第一个函数参数(onRejected)中拿到
[rule--]
Promise 的 status:
pending
- 初始的状态,可改变,
- 一个promise 在
resolve
/reject
前都处于这个状态 - 我们可以通过调用
resolve
方法或reject
方法,让这个promise,变成fulfilled
/rejected
状态;
fulfilled
- 不可变状态
- 在
resolve
之后,变成这个状态,拥有一个value
rejected
- 不可变状态
- 在
reject
之后,变成这个状态,拥有一个reason
then函数:
- 参数:
onFulfilled
必须是函数类型,如果不是,应该被忽略;onRejected
必须是函数类型,如果不是,应该被忽略; onFulfilled
/onRejected
的特性 在promise
变成fulfilled
/rejected
状态的时候,应该调用onFulfilled
/onRejected
; 在promise
变成fulfilled
/rejected
状态之前,不应该被调用; 只能被调用一次。
[--rule]
一、申明promise类
进行初始化的一些操作
js
function MyPromise(callback) {
// 初始化状态为 pending
this.status = 'pending';
// 初始化成功状态的值
this.value = undefined;
// 初始化失败状态的值
this.reason = undefined;
// 定义 resolve 函数
this.resolve = value => {
if (this.status === 'pending') {
// 更新状态为 fulfilled
this.status = 'fulfilled';
// 存储成功状态的值
this.value = value;
}
};
// 定义 reject 函数
this.reject = reason => {
if (this.status === 'pending') {
// 更新状态为 rejected
this.status = 'rejected';
// 存储失败状态的值
this.reason = reason;
}
};
// 调用回调函数,将 resolve 和 reject 传递给它
callback(this.resolve, this.reject);
}
二、写then方法
onFulfilled
和onRejected
分别是用户在then
中自己定义的成功和失败的回调方法但是并非无脑执行,只有状态对应
fulfilled
/rejected
才可以,所以需要进行一个发布订阅下文中
onFulfilledCallbacks
和onRejectedCallbacks
用来解决异步调用的问题。
流程描述:
- 一个
promise
进来以后,首先callback
- 如果
callback
中的resolve
是同步函数,后续then
直接走fulfilled
或者rejected
对应的方法 - 否则走
pending
对应的方法存储起来,直到callback
中的resolve
这个异步函数走完,根据此时的状态,调用存储的回调函数数组来循环调用
js
function MyPromise(callback) {
// 存储成功状态的回调函数
this.onFulfilledCallbacks = [];
// 存储失败状态的回调函数
this.onRejectedCallbacks = [];
...
...
...
// 定义 resolve 函数
this.resolve = value => {
if (this.status === 'pending') {
// 更新状态为 fulfilled
this.status = 'fulfilled';
// 存储成功状态的值
this.value = value;
// 执行所有成功状态的回调函数
this.onFulfilledCallbacks.forEach(cb => cb());
}
};
// 定义 reject 函数
this.reject = reason => {
if (this.status === 'pending') {
// 更新状态为 rejected
this.status = 'rejected';
// 存储失败状态的值
this.reason = reason;
// 执行所有失败状态的回调函数
this.onRejectedCallbacks.forEach(cb => cb());
}
};
// 调用回调函数,将 resolve 和 reject 传递给它
try {
callback(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected = typeof onRejected === "function" ? onRejected : (reason) => { throw reason };
// 创建一个新的 Promise 对象
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try {
// 执行 onFulfilled 回调函数
const x = onFulfilled(this.value);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
})
}
if (this.status === 'rejected') {
setTimeout(() => {
try {
// 执行 onRejected 回调函数
const x = onRejected(this.reason);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
})
}
if (this.status === 'pending') {
// 将 onFulfilled 和 onRejected 保存起来
// 等待异步操作完成后再执行
this.onResolvedCallbacks.push(() => {
if (this.status === 'fulfilled') {
try {
// 执行 onFulfilled 回调函数
const x = onFulfilled(this.value);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
});
this.onRejectedCallbacks.push(() => {
if (this.status === 'rejected') {
try {
// 执行 onRejected 回调函数
const x = onRejected(this.reason);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
});
} else {
// 执行完所有回调函数之后,清空回调数组
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
}
});
// 返回新的 Promise 对象
return promise2;
}
[qestion]
[rule--]
onFulfilledCallbacks
和 onRejectedCallbacks
为什么是数组?
- 因为then可以被链式调用,且是按照then的顺序执行,或者说注册顺序
- 保证then之后的所有逻辑在拿到promise完成值之后执行
- 同时数组每个function返回的都是一个promise
[--rule]
三、写resolvePromise方法
--- 下文看看就行,不需要记忆 --- resolvePromise 的规范:
- 如果 promise2和x相等,那么 reject TypeError
- 如果 x 是一个 promise 如果 x 是 pending 态,那么 promise 必须要在 pending,直到 x 变成 fulfilled or rejected. 如果 x 被 fulfilled,fulfill promise with the same value. 如果 x 被 rejected,reject promise with the same reason.
- 如果 x 是一个 object 或者 是一个 function let then =x.then. 如果 x.then 这步出错,那么 reject promise with e as the reason. 如果 then 是一个函数,then.call(x,resolvePromiseFn,rejectPromise) resolvePromiseFn的入参是y,执行resolvePromise(promise2,y,resolve,reject); rejectPromise的入参是r,reject promise with r. 如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。 如果调用then抛出异常e 如果 resolvePromise或rejectPromise 已经被调用,那么忽略 否则,reject promise with e as the reason 如果 then不是-个function.fulfill promise with x.
[--rule]
js
function resolvePromise(promise2, x, resolve, reject) {
// 如果 promise2 和 x 是同一个对象,则抛出一个类型错误,因为这样会导致循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 判断 x 是否是一个 Promise 实例
if (x instanceof MyPromise) {
// 如果 x 是一个 Promise 实例,则执行 x,并在其 resolve 或 reject 后再执行 promise2 的 resolve 或 reject
x.then(function (value) {
resolve(value);
}, function (reason) {
reject(reason);
});
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 如果 x 不是一个 Promise 实例 ,是一个对象或者函数
let then;
try {
then = x.then;
} catch (e) {
// 如果获取 then 属性时抛出异常,则直接 reject 这个异常
return reject(e);
}
if (typeof then === 'function') {
// 如果 then 是一个函数,则将 x 作为 this 执行 then 函数
let called = false;
try {
then.call(x, function (y) {
// 如果 then 被调用过,则忽略后续调用
if (called) return;
called = true;
// 递归调用 resolvePromise,直到解析出一个普通值
resolvePromise(promise2, y, resolve, reject);
}, function (r) {
// 如果 then 被调用过,则忽略后续调用
if (called) return;
called = true;
// 如果调用 then 的过程中出现异常,则将异常作为原因 reject promise2
reject(r);
});
} catch (e) {
// 如果在调用 then 的过程中抛出异常,则如果 then 还未被调用过,则将异常作为原因 reject promise2
if (called) return;
reject(e);
}
} else {
// 如果 x 是一个普通对象,则直接 resolve x
resolve(x);
}
} else {
// 如果 x 是一个普通值,则直接 resolve x
resolve(x);
}
}
四、写catch方法
js
MyPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
五、写finally方法
js
MyPromise.prototype.finally = function (onSettled) {
return this.then(onSettled, onSettled);
}
// 测试
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log('1')
resolve('成功')
}, 1000)
}).finally((e) => {
console.log("finally")
console.log(e)
})
// 1
// finally
// 成功
看起来这样就行了,但是这里实际上是不接受传参的,最后一个不应该是成功,而是undefined才对,所以需要修改一下:
js
MyPromise.prototype.finally = function (onSettled) {
return this.then((data) => {
onSettled();
return data;
}, (reason) => {
onSettled();
throw reason;
});
}
这样还可以将上一个给继承下去。
六、静态方法
MyPromise.resolve()
js
MyPromise.resolve = function (data) {
if (data instanceof MyPromise) {
return data
}
return new MyPromise((resolve, reject) => {
resolve(data);
});
}
MyPromise.reject()
js
MyPromise.reject = function (data) {
return new MyPromise((resolve, reject) => {
reject(data);
});
}
MyPromise.all()
js
// 需要满足有序、如果一个报错,则返回报错的reason
MyPromise.all = function (proms) {
return new MyPromise((resolve, reject) => {
const result = [];
let count = 0; // number of promises
let fulfilledCount = 0;
// 为什么使用for of而不是for,因为进来的可能是一个迭代器
for (const p of proms) {
let cur = count
count++;
MyPromise.resolve(p).then((data) => {
fulfilledCount++;
result[cur] = data
if (fulfilledCount === count) {
resolve(result);
}
}, reject)
}
if (count === 0) resolve(result);
});
}
// 测试
MyPromise.all([
MyPromise.resolve(1),
MyPromise.reject(2),
MyPromise.reject(3),
4
]).then(res => {
console.log(res);
}, res => {
console.log(res);
})
MyPromise.allSettled()
直接利用all就行了,保证all里面每个返回都是resolve。
js
MyPromise.allSettled = function (proms) {
const ps = [];
for (const p of proms) {
ps.push(MyPromise.resolve(p).then((value) => ({
value,
status: "fulfilled"
}), (reason) => ({
reason,
status: "rejected"
})))
}
return MyPromise.all(ps);
}
// 测试
MyPromise.allSettled([
MyPromise.resolve(1),
MyPromise.reject(2),
MyPromise.reject(3),
4
]).then(res => {
console.log(res);
}, res => {
console.log(res);
})
MyPromise.race()
js
MyPromise.race = function (proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then((data) => {
resolve(data);
}, reject)
}
});
}
// 测试
MyPromise.race([
new MyPromise((resolve) => {
setTimeout(() => {
resolve(1)
}, 500)
}),
new MyPromise((resolve) => {
setTimeout(() => {
resolve(2)
}, 1000)
}),
]).then(res => {
console.log(res);
}, res => {
console.log(res);
})
七、全部代码
js
function MyPromise(callback) {
// 初始化状态为 pending
this.status = 'pending';
// 初始化成功状态的值
this.value = undefined;
// 初始化失败状态的值
this.reason = undefined;
// 存储成功状态的回调函数
this.onResolvedCallbacks = [];
// 存储失败状态的回调函数
this.onRejectedCallbacks = [];
// 定义 resolve 函数
this.resolve = value => {
if (this.status === 'pending') {
// 更新状态为 fulfilled
this.status = 'fulfilled';
// 存储成功状态的值
this.value = value;
// 执行所有成功状态的回调函数
this.onResolvedCallbacks.forEach(cb => cb());
}
};
// 定义 reject 函数
this.reject = reason => {
if (this.status === 'pending') {
// 更新状态为 rejected
this.status = 'rejected';
// 存储失败状态的值
this.reason = reason;
// 执行所有失败状态的回调函数
this.onRejectedCallbacks.forEach(cb => cb());
}
};
// 调用回调函数,将 resolve 和 reject 传递给它
try {
callback(this.resolve, this.reject);
} catch (error) {
reject(error);
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 如果 promise2 和 x 是同一个对象,则抛出一个类型错误,因为这样会导致循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 判断 x 是否是一个 Promise 实例
if (x instanceof MyPromise) {
// 如果 x 是一个 Promise 实例,则执行 x,并在其 resolve 或 reject 后再执行 promise2 的 resolve 或 reject
x.then(function (value) {
resolve(value);
}, function (reason) {
reject(reason);
});
} else if (x != null && (typeof x === 'object' || typeof x === 'function')) {
// 如果 x 不是一个 Promise 实例 ,是一个对象或者函数
let then;
try {
then = x.then;
} catch (e) {
// 如果获取 then 属性时抛出异常,则直接 reject 这个异常
return reject(e);
}
if (typeof then === 'function') {
// 如果 then 是一个函数,则将 x 作为 this 执行 then 函数
let called = false;
try {
then.call(x, function (y) {
// 如果 then 被调用过,则忽略后续调用
if (called) return;
called = true;
// 递归调用 resolvePromise,直到解析出一个普通值
resolvePromise(promise2, y, resolve, reject);
}, function (r) {
// 如果 then 被调用过,则忽略后续调用
if (called) return;
called = true;
// 如果调用 then 的过程中出现异常,则将异常作为原因 reject promise2
reject(r);
});
} catch (e) {
// 如果在调用 then 的过程中抛出异常,则如果 then 还未被调用过,则将异常作为原因 reject promise2
if (called) return;
reject(e);
}
} else {
// 如果 x 是一个普通对象,则直接 resolve x
resolve(x);
}
} else {
// 如果 x 是一个普通值,则直接 resolve x
resolve(x);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected = typeof onRejected === "function" ? onRejected : (reason) => { throw reason };
// 创建一个新的 Promise 对象
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
try {
// 执行 onFulfilled 回调函数
const x = onFulfilled(this.value);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
if (this.status === 'rejected') {
try {
// 执行 onRejected 回调函数
const x = onRejected(this.reason);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
if (this.status === 'pending') {
// 将 onFulfilled 和 onRejected 保存起来
// 等待异步操作完成后再执行
this.onResolvedCallbacks.push(() => {
if (this.status === 'fulfilled') {
try {
// 执行 onFulfilled 回调函数
const x = onFulfilled(this.value);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
});
this.onRejectedCallbacks.push(() => {
if (this.status === 'rejected') {
try {
// 执行 onRejected 回调函数
const x = onRejected(this.reason);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将异常作为失败状态的值
reject(error);
}
}
});
} else {
// 执行完所有回调函数之后,清空回调数组
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
}
});
// 返回新的 Promise 对象
return promise2;
}
MyPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
MyPromise.prototype.finally = function (onSettled) {
return this.then((data) => {
onSettled();
return data;
}, (reason) => {
onSettled();
throw reason;
});
}
MyPromise.resolve = function (data) {
if (data instanceof MyPromise) {
return data
}
return new MyPromise((resolve, reject) => {
resolve(data);
});
}
MyPromise.reject = function (data) {
return new MyPromise((resolve, reject) => {
reject(data);
});
}
// 需要满足有序、如果一个报错,则返回报错的reason
MyPromise.all = function (proms) {
return new MyPromise((resolve, reject) => {
const result = [];
let count = 0; // number of promises
let fulfilledCount = 0;
// 为什么使用for of而不是for,因为进来的可能是一个迭代器
for (const p of proms) {
let cur = count
count++;
MyPromise.resolve(p).then((data) => {
fulfilledCount++;
result[cur] = data
if (fulfilledCount === count) {
resolve(result);
}
}, reject)
}
if (count === 0) resolve(result);
});
}
MyPromise.allSettled = function (proms) {
const ps = [];
for (const p of proms) {
ps.push(MyPromise.resolve(p).then((value) => ({
value,
status: "fulfilled"
}), (reason) => ({
reason,
status: "rejected"
})))
}
return MyPromise.all(ps);
}
MyPromise.race = function (proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then((data) => {
resolve(data);
}, reject)
}
});
}
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log('1')
resolve('成功')
}, 1000)
})
promise.then(value => {
console.log(value)
return "第一次"
}).then(value => {
console.log(value)
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('第二次处理结果');
}, 1000);
});
}).then(value => {
console.log(value);
throw new Error('抛出异常');
}).catch(error => {
console.log("到最后了:" + error);
});
执行结果
js
// 1
// 成功
// 第一次
// 第二次处理结果
// 到最后了:Error: 抛出异常
完结撒花