diff --git a/Promise.js b/Promise.js index 6aa112b..3551373 100644 --- a/Promise.js +++ b/Promise.js @@ -24,7 +24,16 @@ Promise.cooperative = function(){ { get isSet(){ return handlers === false }, - set: function(value){ + // + // Resolve promise with value... + // .set(value) + // -> this + // + // Reject promise with value... + // .set(value, false) + // -> this + // + set: function(value, resolve=true){ // can't set twice... if(this.isSet){ throw new Error('Promise.cooperative().set(..): can not set twice') } @@ -34,7 +43,9 @@ Promise.cooperative = function(){ value.catch(handlers.reject) // resolve with value... } else { - handlers.resolve(value) } + resolve ? + handlers.resolve(value) + : handlers.reject(value) } // cleanup and prevent setting twice... handlers = false return this }, @@ -45,23 +56,49 @@ Promise.cooperative = function(){ //--------------------------------------------------------------------- // promise iterators... +// XXX should this be aborted on reject??? var IterablePromise = module.IterablePromise = Promise.iter = object.Constructor('IterablePromise', Promise, { - // XXX do we need this to be public??? + // + // Format: + // [ + // [ ], + // , + // ... + // ] + // __list: null, + // iterator methods... // // These will return a new IterablePromise instance... // + // When called from a resolved promise these will return a new + // resolved promise with updated values... + // + // When called from a rejected promise these will return a rejected + // with the same reason promise... + // + // // NOTE: these are different to Array's equivalents in that the handler // is called not in the order of the elements but rather in order // of promise resolution... // NOTE: index of items is unknowable because items can expand on // contract depending on handlrs (e.g. .filter(..) can remove // items)... + // This the following can not be implemented here: + // .slice(..) + // .splice(..) + // .at(..) + // [Symbol.iterator]() - needs to be sync... + // The followng methods are questionable: + // .indexOf(..) + // .includes(..) + // .some(..) / .every(..) + // .sort(..) map: function(func){ return this.constructor(this.__list, function(e){ return [func(e)] }) }, @@ -84,33 +121,37 @@ object.Constructor('IterablePromise', Promise, { : e }) }, - // NOTE: these return a Promise instance... - then: function(handler){ - var that = this - return new Promise(function(resolve, reject){ - // then... - object.parentCall(IterablePromise.prototype.then, that, - function(){ - resolve(handler.call(this, ...arguments)) }) - that.catch(reject) }) }, - catch: function(handler){ - var that = this - return new Promise(function(resolve, reject){ - that.then(resolve) - // catch... - object.parentCall(IterablePromise.prototype.catch, that, - function(){ - reject(handler.call(this, ...arguments)) }) }) }, - finally: function(handler){ - var that = this - return new Promise(function(resolve, reject){ - // bind promise state to that... - that.then(resolve) - that.catch(reject) - // finally... - object.parentCall(IterablePromise.prototype.finally, that, - function(){ - handler.call(this, ...arguments) }) }) }, + // XXX do we need: + // .pop() + // .shift() + // .first() / .last() + // XXX these can change the "resolved" state... + // ...i.e. return a pending promise when called from a fulfilled + // promise.... + // .concat(..) + // .push(..) + // .unshift(..) + // .first(..) / .last(..) + + + // Overload .then(..), .catch(..) and .finally(..) to return a plain + // Promise instnace... + // + // NOTE: .catch(..) and .finally(..) are implemented through .then(..) + // so we do not need to overload those... + then: function(onfulfilled, onrejected){ + return new Promise( + function(resolve, reject){ + object.parentCall(IterablePromise.prototype.then, this, + // NOTE: resolve(..) / reject(..) return undefined so + // we can't pass them directly here... + function(res){ + resolve(res) + return res }, + function(res){ + reject(res) + return res }) }.bind(this)) + .then(...arguments) }, // @@ -131,6 +172,17 @@ object.Constructor('IterablePromise', Promise, { // items... // XXX we can make the index a promise, then if the client needs // the value they can wait for it... + // + // + // Clone the iterator... + // Promise.iter([ .. ], false) + // -> iterable-promise + // + // Create a rejected iterator... + // Promise.iter(false) + // -> iterable-promise + // + // __new__: function(_, list, handler){ var promise @@ -140,15 +192,18 @@ object.Constructor('IterablePromise', Promise, { // NOTE: this is here for Promise compatibilty... if(typeof(list) == 'function'){ return list.call(this, ...arguments) } + // initial reject... + if(list === false){ + return reject() } promise = {resolve, reject} }], IterablePromise) if(promise){ // apply handler(..) to the list... + // // NOTE: the top level promises are not wrapped in arrays... - // XXX should this be aborted on reject??? - // ...need to be able to do a deep abort... list = + // apply the handler... handler ? list.map(function(block){ return (block instanceof Array ? @@ -164,11 +219,13 @@ object.Constructor('IterablePromise', Promise, { // basic value... : handler(e) }) }) .flat() + // normal constructor... : handler === undefined ? list.map(function(e){ return e instanceof Promise ? e : [e] }) + // clone... : list.slice() Object.defineProperty(obj, '__list', { @@ -180,7 +237,6 @@ object.Constructor('IterablePromise', Promise, { Promise.all(list) .then(function(res){ promise.resolve(res.flat()) }) - // XXX do we need to pass the results here??? .catch(promise.reject) } return obj }, diff --git a/package.json b/package.json index 182ea3c..6dab3be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-types", - "version": "3.7.8", + "version": "3.7.9", "description": "Generic JavaScript types and type extensions...", "main": "main.js", "scripts": {