Created
March 10, 2017 22:15
-
-
Save kevincennis/8709ba8c053d7e2979b5e2bee746d2b8 to your computer and use it in GitHub Desktop.
Prom
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
const PENDING = Symbol('PENDING'); | |
const RESOLVED = Symbol('RESOLVED'); | |
const REJECTED = Symbol('REJECTED'); | |
const FULFILL = Symbol('FULFILL'); | |
const cache = new WeakMap(); | |
const queue = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout; | |
class Prom { | |
constructor( fn ) { | |
const state = { | |
status: PENDING, | |
value: null, | |
success_handlers: [], | |
error_handlers: [] | |
}; | |
cache.set( this, state ); | |
const resolve = val => { | |
if ( val && typeof val.then === 'function' ) { | |
return val.then( resolve ).catch( reject ); | |
} | |
if ( state.status === PENDING ) { | |
state.status = RESOLVED; | |
state.value = val; | |
this[ FULFILL ](); | |
} | |
}; | |
const reject = err => { | |
if ( state.status === PENDING ) { | |
state.status = REJECTED; | |
state.value = err; | |
this[ FULFILL ](); | |
} | |
}; | |
try { | |
fn( resolve, reject ); | |
} catch ( e ) { | |
setImmediate( () => reject( e ), 0 ); | |
} | |
} | |
then( fn ) { | |
const state = cache.get( this ); | |
switch( state.status ) { | |
case RESOLVED: | |
return new Prom( ( resolve, reject ) => { | |
try { | |
const result = fn( state.value ); | |
resolve( result ); | |
} catch( err ) { | |
reject( err ); | |
} | |
}); | |
case REJECTED: | |
return new Prom( ( resolve, reject ) => reject( state.value ) ); | |
case PENDING: | |
return new Prom( ( resolve, reject ) => { | |
const handler = val => { | |
try { | |
const result = fn( val ); | |
resolve( result ); | |
} catch( err ) { | |
reject( err ); | |
} | |
}; | |
state.success_handlers.push( handler ); | |
state.error_handlers.push( reject ); | |
}); | |
} | |
} | |
catch( fn ) { | |
const state = cache.get( this ); | |
switch( state.status ) { | |
case RESOLVED: | |
return new Prom( resolve => resolve( state.value ) ); | |
case REJECTED: | |
return new Prom( ( resolve, reject ) => { | |
try { | |
const result = fn( val ); | |
resolve( result ); | |
} catch( err ) { | |
reject( err ); | |
} | |
}); | |
case PENDING: | |
return new Prom( ( resolve, reject ) => { | |
const handler = val => { | |
try { | |
const result = fn( val ); | |
resolve( result ); | |
} catch( err ) { | |
reject( err ); | |
} | |
}; | |
state.success_handlers.push( resolve ); | |
state.error_handlers.push( handler ); | |
}); | |
} | |
} | |
[ FULFILL ]() { | |
const state = cache.get( this ); | |
const { status, value, success_handlers, error_handlers } = state; | |
const fns = status === RESOLVED ? success_handlers : error_handlers; | |
fns.forEach( fn => fn( value ) ); | |
} | |
static resolve( val ) { | |
return new Prom( resolve => resolve( val ) ); | |
} | |
static reject( val ) { | |
return new Prom( ( resolve, reject ) => reject( val ) ); | |
} | |
static all( proms ) { | |
const values = []; | |
return new Prom( ( resolve, reject ) => { | |
function success( val ) { | |
if ( values.push( val ) === proms.length ) { | |
resolve( values ); | |
} | |
} | |
proms.forEach( prom => prom.then( success ).catch( reject ) ); | |
}); | |
} | |
static race( proms ) { | |
return new Prom( ( resolve, reject ) => { | |
proms.forEach( prom => prom.then( resolve ).catch( reject ) ); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment