namespace drunk { export interface IThenable < R > { then < U > ( onFulfillment ? , onRejection ? ) : IThenable < U > ; } export interface IPromiseExecutor < R > { ( resolve , reject ) : void ; } enum PromiseState { PENDING , RESOLVED , REJECTED } function noop ( ) { } function init < R > ( promise , executor ) { function resolve < R > ( value ) { resolvePromise ( promise , value ) ; } function reject < R > ( reason ) { rejectPromise ( promise , reason ) ; } try { executor ( resolve , reject ) ; } catch ( e ) { rejectPromise ( promise , e ) ; } } function resolvePromise < R > ( promise , value ) { if ( promise . _state !== PromiseState . PENDING ) { return ; } if ( promise === value ) { publish ( promise , new TypeError ( 'Chaining cycle detected for promise #<Promise>' ) , PromiseState . REJECTED ) ; } else if ( isThenable ( value ) ) { handleThenable ( value , promise ) ; } else { publish ( promise , value , PromiseState . RESOLVED ) ; } } function rejectPromise < R > ( promise , reason ) { if ( promise . _state !== PromiseState . PENDING ) { return ; } if ( promise === reason ) { reason = new TypeError ( 'Chaining cycle detected for promise #<Promise>' ) ; } publish ( promise , reason , PromiseState . REJECTED ) ; } function isThenable ( target ) { return target && typeof target . then === 'function' ; } function handleThenable < R > ( thenable , promise ) { let toResolve = value => { resolvePromise ( promise , value ) ; } ; let toReject = reason => { rejectPromise ( promise , reason ) ; } ; if ( thenable instanceof Promise ) { if ( thenable . _state === PromiseState . PENDING ) { subscribe ( thenable , promise , toResolve , toReject ) ; } else if ( thenable . _state === PromiseState . RESOLVED ) { publish ( promise , thenable . _value , PromiseState . RESOLVED ) ; } else { publish ( promise , thenable . _value , PromiseState . REJECTED ) ; } } else { thenable . then ( toResolve , toReject ) ; } } function publish ( promise , value , state ) { promise . _state = state ; promise . _value = value ; asap ( ( ) => { let listeners = promise . _listeners ; let total = listeners . length ; if ( ! total ) { return ; } for ( let i = 0 ; i < total ; i += 3 ) { invokeCallback ( state , listeners [ i ] , listeners [ i + state ] , value ) ; } listeners . length = 0 ; } ) ; } function asap < R > ( callback ) { callback ( ) ; } function invokeCallback < R > ( state , promise , callback , value ) { let hasCallback = typeof callback === 'function' ; let done = false ; let fail = false ; if ( ! promise ) { if ( hasCallback ) { try { callback . call ( undefined , value ) ; } catch ( e ) { setTimeout ( ( ) => { throw e ; } , 0 ) ; } } return ; } if ( promise . _state !== PromiseState . PENDING ) { return ; } if ( hasCallback ) { try { value = callback . call ( undefined , value ) ; done = true ; } catch ( e ) { value = e ; fail = true ; } } if ( hasCallback && done ) { resolvePromise ( promise , value ) ; } else if ( fail ) { rejectPromise ( promise , value ) ; } else if ( state === PromiseState . RESOLVED ) { publish ( promise , value , state ) ; } else { rejectPromise ( promise , value ) ; } } function subscribe < R > ( promise , subPromise , onFulfillment , onRejection ) { let arr = promise . _listeners ; let len = arr . length ; arr [ len + PromiseState . PENDING ] = subPromise ; arr [ len + PromiseState . RESOLVED ] = onFulfillment ; arr [ len + PromiseState . REJECTED ] = onRejection ; } export class Promise < R > implements IThenable < R > { static all < R > ( iterable ) { return new Promise ( ( resolve , reject ) => { let total = iterable . length ; let count = 0 ; let rejected = false ; let result = [ ] ; let check = ( i , value ) => { result [ i ] = value ; if ( ++ count === total ) { resolve ( result ) ; result = null ; } } ; if ( ! total ) { return resolve ( result ) ; } iterable . forEach ( ( thenable , i ) => { if ( ! isThenable ( thenable ) ) { return check ( i , thenable ) ; } thenable . then ( value => { if ( ! rejected ) { check ( i , value ) ; } } , reason => { if ( ! rejected ) { rejected = true ; result = null ; reject ( reason ) ; } } ) ; } ) ; iterable = null ; } ) ; } static race < R > ( iterable ) { return new Promise ( ( resolve , reject ) => { let total = iterable . length ; let ended = false ; let check = ( value , rejected ? ) => { if ( rejected ) { reject ( value ) ; } else { resolve ( value ) ; } ended = true ; } ; for ( let i = 0 , thenable ; i < total ; i ++ ) { thenable = iterable [ i ] ; if ( ! isThenable ( thenable ) ) { resolve ( thenable ) ; break ; } if ( ( thenable instanceof Promise ) && thenable . _state !== PromiseState . PENDING ) { check ( thenable . _value , thenable . _state === PromiseState . REJECTED ) ; break ; } else { thenable . then ( value => check ( value ) , reason => check ( reason , true ) ) ; } } iterable = null ; } ) ; } static resolve < R > ( value ? ) { let promise = new Promise ( noop ) ; if ( ! isThenable ( value ) ) { promise . _state = PromiseState . RESOLVED ; promise . _value = value ; } else { resolvePromise ( promise , value ) ; } return promise ; } static reject < R > ( reason ? ) { let promise = new Promise ( noop ) ; if ( ! isThenable ( reason ) ) { promise . _state = PromiseState . REJECTED ; promise . _value = reason ; } else { resolvePromise ( promise , reason ) ; } return promise ; } static timeout ( delay = 0 ) { return new Promise ( resolve => { setTimeout ( resolve , delay ) ; } ) ; } _state : number = PromiseState . PENDING ; _value : any ; _listeners : any [ ] = [ ] ; constructor constructor ( executor ) { if ( typeof executor !== 'function' ) { throw new TypeError ( "Promise constructor takes a function argument" ) ; } if ( ! ( this instanceof Promise ) ) { throw new TypeError ( "Promise instance must be created by 'new' operator" ) ; } init ( this , executor ) ; } then < U > ( onFulfillment ? , onRejection ? ) { let state = this . _state ; let value = this . _value ; if ( state === PromiseState . RESOLVED && ! onFulfillment ) { return Promise . resolve ( value ) ; } if ( state === PromiseState . REJECTED && ! onRejection ) { return Promise . reject ( value ) ; } let promise = new Promise ( noop ) ; if ( state ) { let callback = arguments [ state - 1 ] ; asap ( ( ) => { invokeCallback ( state , promise , callback , value ) ; } ) ; } else { subscribe ( this , promise , onFulfillment , onRejection ) ; } return promise ; } done < U > ( onFulfillment ? , onRejection ? ) { let state = this . _state ; let value = this . _value ; if ( state ) { let callback = arguments [ state - 1 ] ; asap ( ( ) => { invokeCallback ( state , null , callback , value ) ; } ) ; } else { subscribe ( this , null , onFulfillment , onRejection ) ; } } catch < U > ( onRejection ? ) { return this . then ( null , onRejection ) ; } cancel ( ) { if ( this . _state ) { return ; } rejectPromise ( this , new Error ( 'Canceled' ) ) ; } } }