手写模拟Promise
手写模拟Promise
璃安猫: 该文章中的MyPromise参考其他文章的Promise源码,然后使用自己的思路总结从零开始手写Promise的过程,若其中有不足之处劳烦指正。
分析Promise
Promise五种使用情况
- 链式执行同步任务
new Promise((resolve, reject) => {
resolve('同步任务');
// reject('同步 error');
}).then((value) => {
console.log(value);
return new Promise((resolve) => resolve(222))
}).catch((err) => {
console.log(err);
})
- 链式执行异步任务并使用finally函数
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('异步:ok');
}, 1000);
}).then((value) => {
console.log(value);
}).catch((err) => {
console.log(err);
}).finally((value) => {
console.log(value);
})
- 调用自身
// 第一种 验证then漏洞
const promise = new Promise(resolve => resolve(111))
.then(() => {
return promise
})
promise.then(undefined, err => console.log(err));
// 第二种
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(err=> console.log(err) );
- 使用resolve及reject快速创建Promise对象
Promise.resolve('111').then(v => console.log(v));
Promise.resolve(new Promise(resolve => resolve('222'))).then(v => console.log(v));
Promise.reject('111').catch(err => console.log(err));
Promise.reject(new Promise(resolve => resolve('222'))).catch(v => console.log(v));
- 使用all方法并行执行任务
const arr = ['111', Promise.resolve(222), Promise.resolve(333)];
Promise.all(arr).then(v => console.log(v)).catch(err => console.log(err));
const arr = ['111', Promise.resolve(222), Promise.reject('444'), Promise.resolve('111')];
Promise.all(arr).then(v => console.log(v)).catch(err => console.log(err));
Promsie结构分析
变量
变量名 | 描述 |
---|---|
status | 存储状态 :fulfilled rejected pending |
value | 存储fulfilled状态结果 |
reason | 存储rejected状态结果 |
successCallback[] | 成功回调函数数组 |
failCallback[] | 失败回调函数数组 |
函数
实例方法 | 描述 |
---|---|
resolve | 改变自身状态并存储值 |
reject | 改变自身状态并存储值 |
then | 执行回调函数并实现链式调用 |
catch | 执行失败回调函数并实现链式调用 |
finally | 不论失败或成功都执行回调(不获取结果值,仅传递结果) |
静态方法 | 描述 |
---|---|
resolve | 快速创建成功的Promise |
reject | 快速创建失败的Promise |
all | 实现并行执行Promise任务 |
基础结构代码
// 三个状态值为全局变量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
status = PENDING;
value;
reason;
successCallback = [];
failCallback = [];
// 构造函数
constructor (Fn) {}
// 由于该函数调用在传参函数内部 即 resolve, 若为普通函数this则指向全局
// 因此使用箭头函数将this指向MyPromise对象
resolve = value => {}
// 此处同理
reject = reason => {}
// then及以下的函数使用方式都为 .then , 因此this指向MyPromise 不需要使用箭头函数
then (successCallback, failCallback) {}
catch (failCallback) {}
finally () {}
static resolve () {}
static reject () {}
static all () {}
}
完善constructor & 实现 resolve reject
class MyPromise {
status = PENDING;
value;
reason;
successCallback = [];
failCallback = [];
// 构造函数接收传参
constructor (Fn) {
try {
// 执行传入函数
Fn(this.resolve, this.reject);
} catch (err) {
this.reject(err);
}
}
// 由于该函数调用在传参函数内部 即 resolve, 若为普通函数this则指向全局
// 因此使用箭头函数将this指向MyPromise对象
resolve = value => {
// 状态一经确认不可更改
if(this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value;
// 若有回调函数则逐个执行回调函数
// 注: 此处回调是执行异步任务是status仍未改变 但then已执行,因此会在then中存入回调任务
while(this.successCallback.length) {
// 将任务从头出栈并执行
this.successCallback.shift()();
}
}
// 此处同理
reject = reason => {
if(this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
while(this.failCallback.length) {
this.failCallback.shift()();
}
}
}
实现then
class MyPromise {
// ...
// then及以下的函数使用方式都为 .then , 因此this指向MyPromise 不需要使用箭头函数
then(successCallback, failCallback) {
// 如果没有传入回调函数,则将值继续传递
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => { throw reason };
// 返回promise用于then链式调用
const promise = new MyPromise((resolve, reject) => {
// 判断 .then前的Promise的状态 此处this指向.then前的promise
switch (this.status) {
case FULFILLED: {
// 使用异步任务以延迟执行该代码从而获取当前的promise
setTimeout(() => {
try {
const result = successCallback(this.value);
// 该函数用于判断返回结果是否为自身以及promise等情况
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
};
case REJECTED: {
setTimeout(() => {
try {
const result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
};
// 该情况是promsie中为异步任务,因此执行then时status还未改变
// 因此将回调函数存储起来
case PENDING: {
// 存入成功回调
this.successCallback.push(() => {
setTimeout(() => {
try {
const result = successCallback(this.value);
// 该函数用于判断返回结果是否为自身以及promise等情况
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
// 存入失败回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
}
});
return promise;
}
//...
}
// 处理then返回的promise的结果状态
function resolvePromise(promise, result, resolve, reject) {
// 返回的结果为自身promise 造成循环调用
if (promise === result) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
// 返回结果为promise
if (result instanceof MyPromise) {
result.then(v => resolve(v));
}
// 返回结果为普通值
else {
resolve(result);
}
}
至此,可以使用自己手写的Promise验证开头的 1-3 种使用情况 (除去catch及finally)
验证完毕无误后,接着实现其他方法
实现catch 及 finally
class MyPromsie {
// ....
catch(failCallback) {
return this.then(undefined, failCallback);
}
finally(callback) {
// 执行回调函数,并将上一个promise返回的value继续传递
return this.then(value => {
// 若callback为异步任务则需等待异步任务完成再执行下一个任务
// 因此使用 Promise包装callback 避免不等待callback直接执行下一个任务
// 此外不使用finally回调函数的返回值,只传递上一个任务的值
return new MyPromise(resolve => resolve(callback())).then(() => value);
}, reason => {
return new MyPromise(resolve => resolve(callback())).then(() => { throw reason });
})
}
// ...
}
至此,可以使用自己手写的Promise验证开头的 1-3 种使用情况
验证完毕无误后,接着实现其他方法
实现静态方法resolve及reject,优化finally
class MyPromise {
// ...
finally(callback) {
// 执行回调函数,并将上一个promise返回的value继续传递
return this.then(value => {
// 若callback为异步任务则需等待异步任务完成再执行下一个任务
// 因此使用 Promise包装callback 避免不等待callback直接执行下一个任务
// 此外不使用finally回调函数的返回值,只传递上一个任务的值
return MyPromise.resolve(callback()).then(() => value);
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason });
})
}
static resolve(value) {
// 如果value是promise则直接返回
if (value instanceof MyPromise) return value;
// 如果value是普通值则创建返回
else {
return new MyPromise((resolve) => resolve(value));
}
}
static reject(reason) {
// 如果value是promise则直接返回
if (reason instanceof MyPromise) return reason;
// 如果value是普通值则创建返回
else {
return new MyPromise((resolve, reject) => reject(reason));
}
}
// ...
}
至此,可以使用自己手写的Promise验证开头的 1-4 种使用情况
验证完毕无误后,接着实现其他方法
实现all方法
class MyPromise {
// ...
static all(arr) {
// 返回一个promise
return new MyPromise((resolve, reject) => {
// 用于记录返回结果
const result = [];
function addData (i, value) {
result[i] = value;
//判断结果数量是否对应 用于等待异步处理的结果
if (result.length === arr.length) {
resolve(result);
}
}
arr.forEach((value, i) => {
// 如果value为promise
if (value instanceof MyPromise) {
value.then(v => addData(i, v), err => reject(err));
}
// 如果value为普通值
else {
addData(i, value);
}
})
})
}
}
至此,可以使用自己手写的Promise验证开头的 1-5 种使用情况
验证完毕无误后,Promise功能基本实现
完整的MyPromise代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
status = PENDING;
value;
reason;
successCallback = [];
failCallback = [];
// 构造函数接收传参
constructor(Fn) {
try {
// 执行传入函数
Fn(this.resolve, this.reject);
} catch (err) {
this.reject(err);
}
}
// 由于该函数调用在传参函数内部 即 resolve, 若为普通函数this则指向全局
// 因此使用箭头函数将this指向MyPromise对象
resolve = value => {
// 状态一经确认不可更改
if (this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value;
// 若有回调函数则逐个执行回调函数
// 注: 此处回调是执行异步任务是status仍未改变 但then已执行,因此会在then中存入回调任务
while (this.successCallback.length) {
// 将任务从头出栈并执行
this.successCallback.shift()();
}
}
// 此处同理
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
while (this.failCallback.length) {
this.failCallback.shift()();
}
}
// then及以下的函数使用方式都为 .then , 因此this指向MyPromise 不需要使用箭头函数
then(successCallback, failCallback) {
// 如果没有传入回调函数,则将值继续传递
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => { throw reason };
// 返回promise用于then链式调用
const promise = new MyPromise((resolve, reject) => {
// 判断 .then前的Promise的状态 此处this指向.then前的promise
switch (this.status) {
case FULFILLED: {
// 使用异步任务以延迟执行该代码从而获取当前的promise
setTimeout(() => {
try {
const result = successCallback(this.value);
// 该函数用于判断返回结果是否为自身以及promise等情况
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
};
case REJECTED: {
setTimeout(() => {
try {
const result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
};
// 该情况是promsie中为异步任务,因此执行then时status还未改变
// 因此将回调函数存储起来
case PENDING: {
// 存入成功回调
this.successCallback.push(() => {
setTimeout(() => {
try {
const result = successCallback(this.value);
// 该函数用于判断返回结果是否为自身以及promise等情况
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
// 存入失败回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
}
});
return promise;
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
finally(callback) {
// 执行回调函数,并将上一个promise返回的value继续传递
return this.then(value => {
// 若callback为异步任务则需等待异步任务完成再执行下一个任务
// 因此使用 Promise包装callback 避免不等待callback直接执行下一个任务
// 此外不使用finally回调函数的返回值,只传递上一个任务的值
return MyPromise.resolve(callback()).then(() => value);
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason });
})
}
static resolve(value) {
// 如果value是promise则直接返回
if (value instanceof MyPromise) return value;
// 如果value是普通值则创建返回
else {
return new MyPromise((resolve) => resolve(value));
}
}
static reject(reason) {
// 如果value是promise则直接返回
if (reason instanceof MyPromise) return reason;
// 如果value是普通值则创建返回
else {
return new MyPromise((resolve, reject) => reject(reason));
}
}
static all(arr) {
// 返回一个promise
return new MyPromise((resolve, reject) => {
// 用于记录返回结果
const result = [];
function addData (i, value) {
result[i] = value;
// 判断结果数量是否对应 用于等待异步处理的结果
if (result.length === arr.length) {
resolve(result);
}
}
arr.forEach((value, i) => {
// 如果value为promise
if (value instanceof MyPromise) {
value.then(v => addData(i, v), err => reject(err));
}
// 如果value为普通值
else {
addData(i, value);
}
})
})
}
}
// 处理then返回的promise的结果状态
function resolvePromise(promise, result, resolve, reject) {
// 返回的结果为自身promise 造成循环调用
if (promise === result) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
// 返回结果为promise
if (result instanceof MyPromise) {
result.then(v => resolve(v));
}
// 返回结果为普通值
else {
resolve(result);
}
}