-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
手写题:Promise #9
Labels
Comments
支持 HBS & developer-plus🏅 /**
* 分析
* 1. 通过 new Promise 语法发现 ,Promise 就是一个类 ,并且在创建这个类的时候需要一个参数,它会立即执行
*
* 2. Promise 中有3中状态,分别为 成功 fulfilled、失败 rejected 、等待 pending
* 状态走向:
* pending -> fulfilled
* or
* pending -> rejected
* 只要状态确定,将不可更改。
*
* 3. resolve 和 reject 就是用来更改状态的
* resolve:fulfilled
* reject:rejected
*
* 4. then 方法判断状态 成功调用成功回调,失败调用失败回调函数
*
* 5. 成功回调有一个参数 表示成功之后的值,失败回调也有一个参数表示失败之后的值
*
* 6. 通过 new 出来的 promise 对象 只有 then 、catch 方法成员,所以 status 、value 、等是私有属性,外部无法访问
* 为了防止直接通过 promise.status 进行修改状态
*
*/
/**
* 等待
*/
const PENDING = "pending";
/**
* 成功
*/
const FULFILLED = "fulfilled";
/**
* 失败
*/
const REJECTED = "rejected";
/**
* 私有属性
* 在最新的 ES 规范中 以及有 private 关键字 来设置私有属性,这样更直观、简单
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_class_fields
*
* 当然在 TypeScript 中已经支持此特性。
*/
const _status = Symbol();
const _value = Symbol();
const _reason = Symbol();
const _resolve = Symbol();
const _reject = Symbol();
const _successCallback = Symbol();
const _failCallback = Symbol();
class MyPromise {
constructor(executor) {
// 私有属性初始化
// 初始化为数组 解决 多次 promise.then() 情况
this[_successCallback] = [];
this[_failCallback] = [];
/**
* 成功方法
*/
this[_resolve] = (value) => {
// 如果状态不是等待中,直接return
if (this[_status] !== PENDING) return;
// 状态改为成功
this[_status] = FULFILLED;
// 保存成功的值
this[_value] = value;
// 如果成功回调存在就调用执行它
// this[_successCallback] && this[_successCallback](value)
while (this[_successCallback].length) this[_successCallback].shift()();
};
/**
* 失败方法
*/
this[_reject] = (reason) => {
// 如果状态不是等待中,直接return
if (this[_status] !== PENDING) return;
// 状态改为失败
this[_status] = REJECTED;
// 保存失败的值
this[_reason] = reason;
// 如果失败回调存在就调用执行它
// this[_failCallback] && this[_failCallback](reason)
while (this[_failCallback].length) this[_failCallback].shift()();
};
/**
* promise 状态 初始化
*/
this[_status] = PENDING;
// 立即执行执行器 并捕获错误
try {
executor(this[_resolve], this[_reject]);
} catch (error) {
this[_reject](error);
}
}
then(successCallback, failCallback) {
// 处理then 参数可选情况
successCallback = successCallback ? successCallback : (value) => value;
failCallback = failCallback
? failCallback
: (reason) => {
throw reason;
};
// then 链式调用 所以需要返回 MyPromise
const promise = new MyPromise((resolve, reject) => {
// 判断状态 是 成功 还是 失败
if (this[_status] === FULFILLED) {
// 写成异步 让new MyPromise 先创建完成
setTimeout(() => {
try {
const prevVal = successCallback && successCallback(this[_value]);
resolvePromise(promise, prevVal, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this[_status] === REJECTED) {
// 写成异步 让new MyPromise 先创建完成
setTimeout(() => {
try {
const prevVal = failCallback && failCallback(this[_reason]);
resolvePromise(promise, prevVal, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else {
// 异步情况
// 把回调函数储存起来 当异步代码执行 resolve or reject 时执行回调函数
this[_successCallback].push(() => {
// 写成异步 让new MyPromise 先创建完成
setTimeout(() => {
try {
const prevVal = successCallback && successCallback(this[_value]);
resolvePromise(promise, prevVal, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this[_failCallback].push(() => {
// 写成异步 让new MyPromise 先创建完成
setTimeout(() => {
try {
const prevVal = failCallback && failCallback(this[_reason]);
resolvePromise(promise, prevVal, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise;
}
finally(callback) {
return this.then(
(value) => {
return MyPromise.resolve(callback()).then(() => value);
},
(reason) => {
return MyPromise.resolve(callback()).then(() => {
throw reason;
});
}
);
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
static all(arr) {
let result = [];
let index = 0;
// 返回一个promise 对象
return new MyPromise((resolve, reject) => {
function add(key, value) {
result[key] = value;
index++;
if (index === arr.length) {
resolve(result);
}
}
for (let i = 0; i < arr.length; i++) {
const elem = arr[i];
if (elem instanceof MyPromise) {
elem.then(
(value) => add(i, value),
(reason) => reject(reason)
);
} else {
add(i, elem);
}
}
});
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve) => resolve(value));
}
}
// 辅助方法
/**
* 判断 prevVal 是普通值还是 promise 对象
*
* 如果是普通值 直接调用 resolve
*
* 如果是 promise 对象 先查看 promise 对象的结果
* 再根据 返回的结果 决定调用 resolve or reject
*
* 处理 prev 是普通值还是 promise 对象
*/
const resolvePromise = (promise, prevVal, resolve, reject) => {
// 判断自己返回自己
if (promise === prevVal) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
if (prevVal instanceof MyPromise) {
// prevVal.then(value => resolve(value, reason => reject(reason))
prevVal.then(resolve, reject);
} else {
// 普通值
resolve(prevVal);
}
};
MyPromise.defer = MyPromise.deferred = function () {
let dfd = {};
dfd.promise = new MyPromise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = MyPromise; BaboonKing🙈 |
先说结论,洪佬的是正确的,我这个版本比较简陋,细节上是有问题的,仅供大家参考一下哈哈哈,因为我写的 then 不是微任务,会导致执行顺序有问题,正常应该在 then 中先执行完所有同步代码,再去 resolve,我这个会碰到 resolve 就去执行依赖的触发type ResolveType = (value: any) => void
type RejectType = (value: any) => void
type Executor = (resolve: ResolveType, reject: RejectType) => void
export class Promise<T=any> {
public resolve!: ResolveType
public reject!: RejectType
public status!: string
public resolve_executor_value!: any
public reject_executor_value!: any
public resolve_callbacks = []
public reject_callbacks = []
constructor(executor: Executor) {
this.status = 'pending' // 起始等待状态
this.resolve = (successvalue: any): any => {
if(this.status !== 'pending') return
this.status = 'success'
this.resolve_executor_value = successvalue
this.resolve_callbacks.forEach((callback) => callback())
}
this.reject = (failvalue: any): any => {
if(this.status !== 'pending') return
this.status = 'fail'
this.reject_executor_value = failvalue
this.reject_callbacks.forEach((callback) => callback())
}
try {
executor(this.resolve, this.reject)
} catch (err) {
this.status = 'pending'
this.reject(err.toString())
throw new Error('程序终止')
}
}
then(resolveInthen: ResolveType, rejectInthen :RejectType) {
return new Promise((resolve, reject) => {
let result
if(this.status === 'pending') {
this.resolve_callbacks.push(() => {
result = resolveInthen(this.resolve_executor_value)
if (isPromise(result)) {
result.then((res) => { // res 就是后面一次进来时赋成了 this.resolve_executor_value
resolve(res) // 这个地方的 resolve 是 then 中异步 promise 的,而下面的 resolve 是原来的 promise 的,不能混用,所以这里我直接在这调用
}, (err) => { // 这个地方的 then 其实是存给 result 所代表的 promise,而不是 else 中的那个 promise
reject(err)
})
} else {
resolve(result)
}
})
this.reject_callbacks.push(() => {
result = rejectInthen(this.reject_executor_value)
if (isPromise(result)) {
result.then((res) => { // res 就是后面一次进来时赋成了 this.resolve_executor_value
resolve(res) // 这个地方的 resolve 是 then 中异步 promise 的,而下面的 resolve 是原来的 promise 的,不能混用,所以这里我直接在这调用
}, (err) => { // 这个地方的 then 其实是存给 result 所代表的 promise,而不是 else 中的那个 promise
reject(err)
})
} else {
reject(result)
}
})
} else {
if (this.status === 'success') {
resolve(resolveInthen(this.resolve_executor_value))
}
if (this.status === 'fail') {
reject(rejectInthen(this.reject_executor_value))
}
}
})
}
static all(promiseArr: Array<Promise>): Promise {
return new Promise((resolve, reject) => {
let allPromiseResolveSVal = []
let new_index = 0
promiseArr.forEach((promise, index) => {
promise.then((res) => {
process(res, index)
}, (rejectFail) => {
reject(rejectFail)
return
})
})
function process(sval, index) {
allPromiseResolveSVal[index] = sval
if (new_index === promiseArr.length - 1) {
resolve(allPromiseResolveSVal)
}
new_index++
}
})
}
}
function isPromise(val: any): val is Promise {
return typeof val === 'object' && typeof val.then === 'function'
}
export {} |
可以在代码块加一个类型,使代码高亮。 ``` ts |
哈哈哈好! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Promise
是 ES6 中新增的引用类型。在通过
new
创建Promise
对象时,需要传入一个回调函数(executor)。resolve
、reject
;resolve
回调函数时,会执行Promise
对象then
方法传入的回调函数;reject
回调函数时,会执行Promise
对象的catch
方法传入的回调函数。3 种状态
pending
:执行executor
中的代码时,处于该状态;fulfilled
:执行了resolve
时,处于该状态;rejected
:执行了reject
时,处于该状态。9 个方法
then
:当调用resolve
回调函数时,会执行;catch
:当调用reject
回调函数时,会执行;finally
:无论是fulfilled
状态,还是reject
状态,它都会执行;resolve
:相当于new Promise
,并且执行resolve
操作;reject
:相当于new Promise
,并且执行reject
操作;all
:将多个Promise
包裹在一起形成一个新的Promise
;allSettled
:所有的Promise
都有结果,才会有最终的状态;race
:多个Promise
相互竞争,谁先有结果,那么就使用谁的结果;any
:等到一个fulfilled
状态,才会决定新Promise
的状态。如果所有的Promise
都是reject
的,那么会报一个AggregateError
的错误。手写 Promise 思路
一、Promise 类设计
二、构造函数的规划
三、then 方法实现
四、catch 方法
五、finally
六、resolve/reject
七、all/allSettled
核心:要知道
new Promise
的resolve
、reject
在什么情况下执行。all
:情况一:所有的都有结果;
情况二:有一个
reject
。allSettled
:情况:所有都有结果,并且一定执行
resolve
。八、race/any
race
:情况:只要有结果。
any
:情况一:必须等到一个
resolve
结果;情况二:都没有
resolve
,所有的都是reject
,报一个AggregateError
的错误。手写 Promise
The text was updated successfully, but these errors were encountered: