Created
August 3, 2019 22:13
-
-
Save khaosdoctor/e5fa591cce746957f3f189bc371b11ca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export enum PromiseStates { | |
PENDING, | |
FULFILLED, | |
REJECTED | |
} | |
export type ResolveFunction = (value: any) => void | |
export type RejectFunction = (reason: any) => void | |
export type Nullable<T> = T | null | |
export type ExecutorFunction = (resolve: ResolveFunction, reject: RejectFunction) => void |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { PromiseStates, ResolveFunction, RejectFunction, ExecutorFunction, Nullable } from './types/promiseTypes' | |
type HandlerFunction = { | |
onFulfilled: ResolveFunction; | |
onRejected?: Nullable<RejectFunction> | |
} | |
enum ReturnType { | |
SUCCESS = 'success', | |
ERROR = 'error' | |
} | |
export class TypePromise { | |
private state: PromiseStates = PromiseStates.PENDING | |
private finalFunction: Function = () => { } | |
private value: any = null | |
private thenHandlers: HandlerFunction[] = [] | |
constructor (executor: ExecutorFunction) { | |
this.resolve = this.resolve.bind(this) | |
this.reject = this.reject.bind(this) | |
this.handle = this.handle.bind(this) | |
this.doResolve(executor, this.resolve, this.reject) | |
} | |
private fulfill (value: any) { | |
this.state = PromiseStates.FULFILLED | |
this.value = value | |
this.thenHandlers.forEach(this.handle) | |
this.thenHandlers = [] | |
this.finalFunction() | |
} | |
private reject (reason: any) { | |
this.state = PromiseStates.REJECTED | |
this.value = reason | |
this.thenHandlers.forEach(this.handle) | |
this.thenHandlers = [] | |
this.finalFunction() | |
} | |
private resolve (result: any) { | |
try { | |
const then = this.getThen(result) | |
if (then) return this.doResolve(then.bind(result), this.resolve, this.reject) | |
this.fulfill(result) | |
} catch (error) { | |
this.reject(error) | |
} | |
} | |
private getThen (value: any) { | |
const t = typeof value | |
if (value && (t === 'object' || t === 'function')) { | |
const then = value.then | |
if (typeof then === 'function') return then | |
} | |
return null | |
} | |
private handle (handler: HandlerFunction) { | |
if (this.state === PromiseStates.PENDING) return this.thenHandlers.push(handler) | |
if (this.state === PromiseStates.FULFILLED && typeof handler.onFulfilled === 'function') return handler.onFulfilled(this.value) | |
if (this.state === PromiseStates.REJECTED && typeof handler.onRejected === 'function') return handler.onRejected(this.value) | |
} | |
private doResolve (resolverFn: ExecutorFunction, onFulfilled: ResolveFunction, onRejected: RejectFunction) { | |
let done = false | |
try { | |
const handleValues = (type: ReturnType) => { | |
return (value: any) => { | |
if (done) return | |
done = true | |
return { | |
error: onRejected, | |
success: onFulfilled | |
}[type](value) | |
} | |
} | |
resolverFn(handleValues(ReturnType.SUCCESS), handleValues(ReturnType.ERROR)) | |
} catch (error) { | |
if (done) return | |
done = true | |
onRejected(error) | |
} | |
} | |
private done (onFulfilled: ResolveFunction, onRejected?: Nullable<RejectFunction>) { | |
setTimeout(() => { | |
this.handle({ | |
onFulfilled, | |
onRejected | |
}) | |
}, 0) | |
} | |
then (onFulfilled: ResolveFunction, onRejected?: Nullable<RejectFunction>): TypePromise { | |
return new TypePromise((resolve: ResolveFunction, reject: RejectFunction) => { | |
const handleResult = (type: ReturnType) => { | |
return (result: any) => { | |
try { | |
const executorFunction = type === ReturnType.ERROR ? reject : resolve | |
const checkFunction = type === ReturnType.ERROR ? onRejected : onFulfilled | |
return (typeof checkFunction === 'function') ? executorFunction(checkFunction(result)) : executorFunction(result) | |
} catch (error) { | |
reject(error) | |
} | |
} | |
} | |
return this.done(handleResult(ReturnType.SUCCESS), handleResult(ReturnType.ERROR)) | |
}) | |
} | |
catch (onRejected: RejectFunction) { | |
return new TypePromise((resolve: ResolveFunction, reject: RejectFunction) => { | |
return this.done(resolve, (error: any) => { | |
if (typeof onRejected === 'function') { | |
try { | |
return resolve(onRejected(error)) | |
} catch (error) { | |
reject(error) | |
} | |
} | |
return reject(error) | |
}) | |
}) | |
} | |
finally (finalFunction: Function) { | |
if (typeof finalFunction === 'function') this.finalFunction = finalFunction | |
} | |
} | |
function foo (param: any) { | |
return new TypePromise((resolve, reject) => { | |
if (Math.random() > 0.5) return setTimeout(resolve, 1000, param) | |
return setTimeout(reject, 1000, 'error') | |
}) | |
} | |
(() => { | |
foo(5) | |
.then((value) => console.log(value)) | |
.catch((error) => console.error(error)) | |
.finally(() => console.log('sempre retorna')) | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment