Skip to content

Instantly share code, notes, and snippets.

@kevincennis
Created March 10, 2017 22:15
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 kevincennis/8709ba8c053d7e2979b5e2bee746d2b8 to your computer and use it in GitHub Desktop.
Save kevincennis/8709ba8c053d7e2979b5e2bee746d2b8 to your computer and use it in GitHub Desktop.
Prom
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