ES6手写实现
- promise是一个类,它的构造函数接受一个函数,函数的两个参数也都是函数
- 在传入的函数中执行resolve表示成功,执行reject表示失败,传入的值会传给then方法的回调函数
- promise有一个叫做then的方法,该方法有两个参数,第一个参数是成功之后执行的回调函数,第二个参数是失败之后执行的回调函数。then方法在resolve或者reject执行之后才会执行,并且then方法中的值是传给resolve或reject的参数
- promise支持链式调用
成功、失败,这个很容易想到使用一个状态进行标记,实际上Promise就是这样做的。在Promise中使用了
pending、fulfilled、rejected
来标识当前的状态。
pending
初始状态,既不是成功,也不是失败状态。等待resolve或者reject调用更新状态。fulfilled
意味着操作成功完成。rejected
意味着操作失败。需要注意的一点是,这三个状态之间只存在两个变换关系:
pending
转换为fulfilled
,只能由resolve方法完成转换pending
转换为rejected
,只能由reject方法完成转换
type _Resolve = (value?: any) => any;
type _Reject = (reason?: any) => any;
type Executor = (_resolve: _Resolve, _reject: _Reject) => void;
type Then = (onFullfilled?: _Resolve, onRejected?: _Reject) => WPromise;
type Catch = (onRejected?: _Reject) => WPromise;
type Finally = (onHandler?: _Resolve) => WPromise;
type ParallelPromises = (iterable: WPromise[]) => WPromise;
type Resolve = (value: any) => WPromise;
type Reject = (reason: any) => WPromise;
interface Callback {
onFullfilled?: _Resolve;
onRejected?: _Reject;
nextResolve: _Resolve;
nextReject: _Reject;
}
class WPromise {
private static PENDING = 'PENDING';
private static FULFILLED = 'FULFILLED';
private static REJECTED = 'REJECTED';
private status = WPromise.PENDING;
private value: any;
private reason: any;
private callbacks: Callback[] = [];
private executed: boolean = false;
constructor(executor: Executor) {
executor(this._resolve.bind(this), this._reject.bind(this));
}
then: Then = (onFullfilled, onRejected) => {
return new WPromise((nextResolve, nextReject) => {
this._handler({ onFullfilled, onRejected, nextResolve, nextReject });
});
}
catch: Catch = (onRejected) => {
return this.then(undefined, onRejected);
}
finally: Finally = (onHandler) => {
return this.then(onHandler, onHandler);
}
static resolve: Resolve = (value) => {
if (WPromise._isPromiseLike(value)) {
return value;
}
return new WPromise((resolve) => resolve(value));
}
static reject: Reject = (reason) => {
if (WPromise._isPromiseLike(reason)) {
return reason;
}
return new WPromise((resolve, reject) => reject(reason));
}
static all: ParallelPromises = (iterable) => {
return new WPromise((resolve, reject) => {
const ret: any[] = [];
let count = 0;
Array.from(iterable).forEach((item, index) => {
WPromise.resolve(item).then(data => {
ret[index] = data;
count++;
if (count === iterable.length) {
resolve(ret);
}
}, reject);
});
});
}
static race: ParallelPromises = (iterable) => {
return new WPromise((resolve, reject) => {
Array.from(iterable).forEach(item => {
WPromise.resolve(item).then(resolve, reject);
});
});
}
private static _isPromiseLike = (data: any): boolean => {
return data instanceof WPromise || (['object', 'function'].includes(typeof data) && 'then' in data);
}
private _handler = (callback: Callback) => {
if (this.status === WPromise.PENDING) {
this.callbacks.push(callback);
return;
}
const { onFullfilled, onRejected, nextResolve, nextReject } = callback;
if (this.status === WPromise.FULFILLED) {
const toNextValue = onFullfilled ? onFullfilled(this.value) : this.value;
nextResolve(toNextValue);
return;
}
if (this.status === WPromise.REJECTED) {
const toNextReason = onRejected ? onRejected(this.reason) : this.reason;
nextReject(toNextReason);
}
}
private _resolve: _Resolve = (value) => {
if (this.executed) {
return;
}
this.executed = true;
// 链式调用时,针对下一个的promise
// then方法返回一个promise时,value则返回promise执行的结果
if (WPromise._isPromiseLike(value)) {
value.then(this._resolve, this._reject);
return;
}
this.value = value;
this.status = WPromise.FULFILLED;
this.callbacks.forEach(callback => this._handler(callback));
}
private _reject: _Reject = (reason) => {
if (this.executed) {
return;
}
this.executed = true;
if (WPromise._isPromiseLike(reason)) {
reason.then(this._resolve, this._reject);
return;
}
this.reason = reason;
this.status = WPromise.REJECTED;
this.callbacks.forEach(callback => this._handler(callback));
}
}
Proxy实现localStage代理
type SingleValue = string | number | boolean | null | undefined | object;
type Value = SingleValue | SingleValue[];
export type TargetType = Record<string, Value>;
/**
*
* @param storage the storage used for store, localStorage or sessionStorage.
* @param target the key and default values need store in the storage.
* @param prefix a prefix used for set unique storage key.
* @returns
*/
export function createStorage<T extends TargetType>(storage: Storage, target: T) {
// if the target values is empty. throw error.
if (Object.keys(target).length === 0) {
throw Error('NO empty target!');
}
const handler: ProxyHandler<T> = {
/**
* set prop in storage
* @returns boolean
* @example
* const storageProxy = createStorage(localStorage, '_');
* storageProxy.a = 1;
*/
set(target, prop: string, value) {
if (!Reflect.has(target, prop)) {
return false;
}
(target as TargetType)[prop] = value;
storage.setItem(prop, JSON.stringify(value));
return true;
},
/**
* get prop from storage
* @returns boolean
* @example
* const storageProxy = createStorage(localStorage,{a: ""}, '_');
* console.log(storageProxy.a);
*/
get(_, prop: string) {
if (!Reflect.has(target, prop)) {
return undefined;
}
const storageValue = storage.getItem(prop) || '';
try {
return JSON.parse(storageValue);
} catch (error) {
return storageValue;
}
},
/**
* delete single prop in storage
* @returns boolean
* @example
* const storageProxy = createStorage(localStorage,{a: ""}, '_');
* delete storageProxy.a;
*/
deleteProperty(_, prop: string) {
if (!Reflect.has(target, prop)) {
return false;
}
storage.removeItem(prop);
return true;
},
/**
* clean storage
* @returns boolean
* @example
* const storageProxy = createStorage(localStorage,{a: ""},'_');
* Object.preventExtensions(storageProxy);
*/
preventExtensions(target) {
Object.preventExtensions(target);
Object.keys(target).map((key) => storage.removeItem(key));
return true;
},
};
return new Proxy<T>(target, handler);
}