mirror of
https://github.com/flynx/types.js.git
synced 2025-10-29 10:30:08 +00:00
162 lines
4.8 KiB
JavaScript
162 lines
4.8 KiB
JavaScript
/**********************************************************************
|
|
*
|
|
*
|
|
*
|
|
**********************************************/ /* c8 ignore next 2 */
|
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
(function(require){ var module={} // make module AMD/node compatible...
|
|
/*********************************************************************/
|
|
|
|
var object = require('ig-object')
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
var CooperativePromise =
|
|
module.CooperativePromise =
|
|
Promise.cooperative =
|
|
object.Constructor('CooperativePromise', Promise, {
|
|
get isSet(){
|
|
return !this.__resolve && !this.__reject },
|
|
|
|
set: function(promise){
|
|
if(!this.isSet){
|
|
// non-promise...
|
|
if(promise.catch == null && promise.then == null){
|
|
this.__resolve(promise)
|
|
// promise...
|
|
} else {
|
|
// connect the base and the set promises...
|
|
promise.catch(this.__reject.bind(this))
|
|
promise.then(this.__resolve.bind(this)) }
|
|
// cleanup...
|
|
delete this.__resolve
|
|
delete this.__reject
|
|
|
|
return this }
|
|
|
|
// err: already set...
|
|
throw new Error('CooperativePromise.set(..): can not set twice') },
|
|
|
|
__new__: function(_, func){
|
|
var methods = {}
|
|
var obj = Reflect.construct(CooperativePromise.__proto__, [
|
|
function(resolve, reject){
|
|
methods.resolve = resolve
|
|
methods.reject = reject
|
|
if(func){
|
|
// XXX this can fullfill the promise -- need to keep
|
|
// things consistent...
|
|
return func.call(this, ...arguments) } } ],
|
|
CooperativePromise)
|
|
/*/ if we are fulfilled before being set, we are set :)
|
|
// XXX for some reason this breaks either .__new__(..) if called
|
|
// outside of setTimeout(..) or hangs the promise on resolve
|
|
// if inside...
|
|
// ...the same thing happens if we call .then(..)/.catch(..)
|
|
// The odd thing is that calling .finally(..) later works OK...
|
|
// ...increasing the timeout just delays the hang...
|
|
setTimeout(function(){
|
|
obj.finally(function(){
|
|
delete obj.__resolve
|
|
delete obj.__reject
|
|
}) }, 0)
|
|
//*/
|
|
// XXX revise...
|
|
// XXX can we avoid creating these???
|
|
// ...one way to do this is to create a local .set(..)
|
|
// that whould reference them through closure...
|
|
Object.defineProperties(obj, {
|
|
__resolve: {
|
|
value: methods.resolve,
|
|
enumerable: false,
|
|
configurable: true,
|
|
},
|
|
__reject: {
|
|
value: methods.reject,
|
|
enumerable: false,
|
|
configurable: true,
|
|
},
|
|
})
|
|
return obj },
|
|
/* XXX this for some reason breaks the promise...
|
|
// ...the same thing happens if we call .then(..)/.catch(..)
|
|
__init__: function(){
|
|
// if we are fulfilled before being set, we are set :)
|
|
this.finally(function(){
|
|
delete this.__resolve
|
|
delete this.__reject
|
|
}.bind(this)) },
|
|
//*/
|
|
})
|
|
|
|
|
|
|
|
// XXX EXPERIMENTAL -- this hides internal state (.__resolve(..) / .__reject(..))
|
|
// ...not sure if we actually need to do this...
|
|
var _CooperativePromise =
|
|
module._CooperativePromise =
|
|
//Promise.cooperative =
|
|
object.Constructor('_CooperativePromise', Promise, {
|
|
get isSet(){
|
|
return this.set() },
|
|
|
|
//set: function(){},
|
|
|
|
__new__: function(_, func){
|
|
// internal state...
|
|
// NOTE: when promise is set this will be set to false...
|
|
var methods = {}
|
|
|
|
// instance...
|
|
var obj = Reflect.construct(_CooperativePromise.__proto__, [
|
|
function(resolve, reject){
|
|
methods.resolve = resolve
|
|
methods.reject = reject
|
|
// NOTE: this is here mostly for promise compatibilty...
|
|
if(func){
|
|
// XXX this can resolve/reject a promise -- need to
|
|
// keep things consistent...
|
|
return func.call(this, ...arguments) } } ],
|
|
_CooperativePromise)
|
|
|
|
// if we are fulfilled before being set, we are set :)
|
|
// XXX for some reason this breaks either .__new__(..) if called
|
|
// outside of setTimeout(..) or hangs the promise on resolve
|
|
// if inside...
|
|
setTimeout(function(){
|
|
obj.finally(function(){
|
|
methods = false }) }, 0)
|
|
|
|
// create instance .set(..)
|
|
Object.defineProperty(obj, 'set', {
|
|
value: function(promise){
|
|
// get state...
|
|
if(arguments.length == 0){
|
|
return !methods }
|
|
if(methods){
|
|
// non-promise...
|
|
if(promise.catch == null && promise.then == null){
|
|
methods.resolve(promise)
|
|
// promise...
|
|
} else {
|
|
// connect the base and the set promises...
|
|
promise.catch(methods.reject.bind(this))
|
|
promise.then(methods.resolve.bind(this)) }
|
|
methods = false
|
|
return this }
|
|
// err: already set...
|
|
throw new Error('CooperativePromise.set(..): can not set twice') },
|
|
enumerable: false,
|
|
configurable: true,
|
|
})
|
|
|
|
return obj },
|
|
})
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
* vim:set ts=4 sw=4 : */ return module })
|