reworked parts of iterable promise...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-11-18 01:02:00 +03:00
parent cc223ac031
commit a3fdf45578
2 changed files with 90 additions and 34 deletions

View File

@ -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:
// [
// [ <value> ],
// <promise>,
// ...
// ]
//
__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 },

View File

@ -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": {