Skip to content

Instantly share code, notes, and snippets.

@khaosdoctor
Created August 3, 2019 22:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khaosdoctor/e5fa591cce746957f3f189bc371b11ca to your computer and use it in GitHub Desktop.
Save khaosdoctor/e5fa591cce746957f3f189bc371b11ca to your computer and use it in GitHub Desktop.
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
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