notes, cleanup and refactoring...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-06-11 14:35:16 +03:00
parent cc578c6d99
commit 299f6baee4

View File

@ -39,7 +39,7 @@ var object = require('ig-object')
// Like Promise.all(..) but adds ability to iterate through results
// via generators .map(..)/.reduce(..) and friends...
//
// NOTE: it would be nice to support throwing STOP from the iterable
// NOTE: it would be nice to support throwing STOP (XXX) from the iterable
// promise but...
// - this is more complicated than simply using .smap(..) instead
// of .map(..) because the list can contain async promises...
@ -49,11 +49,21 @@ var object = require('ig-object')
// - another issue here is that the stop would happen in order of
// execution and not order of elements...
// XXX though stopping within a single level might be useful...
//
// NOTE: the following can not be implemented here:
// .splice(..) - can't both modify and return
// a result...
// .pop() / .shift() - can't modify the promise, use
// .first() / .last() instead.
// [Symbol.iterator]() - needs to be sync and we can't
// know the number of elements to
// return promises before the whole
// iterable promise is resolved.
// NOTE: we are not using async/await here as we need to control the
// type of promise returned in cases where we know we are returning
// an array...
//
// XXX how do we handle errors/rejections???
// XXX should these be exported???
var iterPromiseProxy =
//module.iterPromiseProxy =
@ -71,6 +81,9 @@ function(name){
var IterablePromise =
module.IterablePromise =
object.Constructor('IterablePromise', Promise, {
// packed array...
//
// Holds promise state.
//
// Format:
// [
@ -87,12 +100,16 @@ object.Constructor('IterablePromise', Promise, {
//
// NOTE: in general iterable promises are implicitly immutable, so
// it is not recomended to ever edit this inplace...
// NOTE: we are not isolation any internals to enable users to
// responsibly extend the code.
__list: null,
// low-level .__list handlers/helpers...
//
// NOTE: these can be useful for debugging and extending...
__pack: function(list, handler){
//
// pack and oprionally transform/handle an array (sync)...
__pack: function(list, handler=undefined){
var that = this
// handle iterable promise list...
if(list instanceof IterablePromise){
@ -120,7 +137,8 @@ object.Constructor('IterablePromise', Promise, {
: !handle ?
elem
: handler(elem) }) },
__handle: function(list, handler){
// transform/handle packed array (sync)...
__handle: function(list, handler=undefined){
var that = this
if(typeof(list) == 'function'){
handler = list
@ -144,18 +162,16 @@ object.Constructor('IterablePromise', Promise, {
return elem.flat() })
: [handler(elem)] })
.flat() },
__unpack: function(list){
// unpack array (async)...
__unpack: async function(list){
list = list
?? this.__list
// handle promise list...
if(list instanceof Promise){
var that = this
return list.then(function(list){
return that.__unpack(list) }) }
// do the work...
return Promise.all(list)
.then(function(list){
return list.flat() }) },
return list instanceof Promise ?
this.__unpack(await list)
// do the work...
: (await Promise.all(list))
.flat() },
// iterator methods...
@ -163,10 +179,10 @@ object.Constructor('IterablePromise', Promise, {
// These will return a new IterablePromise instance...
//
// When called from a resolved promise these will return a new
// resolved promise with updated values...
// resolved promise with updated values... (XXX test)
//
// When called from a rejected promise these will return a rejected
// with the same reason promise...
// with the same reason promise... (XXX test)
//
//
// NOTE: these are different to Array's equivalents in that the handler
@ -175,27 +191,6 @@ object.Constructor('IterablePromise', Promise, {
// NOTE: index of items is unknowable because items can expand and
// contract depending on handlers (e.g. .filter(..) can remove
// items)...
// Thus the following can not be implemented here:
// .splice(..) - can't both modify and return
// a result...
// .pop() / .shift() - can't modify the promise, use
// .first() / .last() instead.
// [Symbol.iterator]() - needs to be sync and we can't
// know the number of elements to
// return promises before the whole
// iterable promise is resolved.
// These are direct poxies requiring the whole promuse to
// resolve:
// .at(..) / .first() / .last()
// - special case: elements
// 0 and -1 can in sime cases
// resolve early...
// .slice(..)
// .entries() / .values() / .keys()
// .indexOf(..)
// .includes(..)
// .some(..) / .every(..)
// .sort(..)
map: function(func){
return this.constructor(this,
function(e){
@ -286,19 +281,17 @@ object.Constructor('IterablePromise', Promise, {
return this.constructor([elem])
.concat(this) },
// XXX can we do these?
// .pop()
// .shift()
// .splice(..)
// ...would be nice if these could stop everything that's not
// needed to execute -- likely not possible (XXX)
// ...these need to somehow both return an element and affect
// the iterator (or return a new one) -- we can trivially do either
// one action within the spec but not both...
// NOTE: this can avoid waiting for the whole promise to resolve only
// for indexes 0 and -1, everything else is non-deterministic and
// we'll have to wait for the whole thing to resolve.
// proxy methods...
//
// These require the whole promise to resolve to trigger.
//
// An exception to this would be .at(0)/.first() and .at(-1)/.last()
// that can get the target element if it's accessible.
//
// NOTE: methods that are guaranteed to return an array will return
// an iterable promise (created with iterPromiseProxy(..))...
//
at: async function(i){
var list = this.__list
return ((i != 0 && i != -1)
@ -331,10 +324,12 @@ object.Constructor('IterablePromise', Promise, {
includes: promiseProxy('includes'),
every: promiseProxy('every'),
// XXX this can be lazy...
// XXX this can be lazy... (???)
some: promiseProxy('some'),
// promise api...
//
// Overload .then(..), .catch(..) and .finally(..) to return a plain
// Promise instnace...
//
@ -360,6 +355,7 @@ object.Constructor('IterablePromise', Promise, {
: p },
// constructor...
//
// Promise.iter([ .. ])
// -> iterable-promise
@ -392,11 +388,6 @@ object.Constructor('IterablePromise', Promise, {
// -> iterable-promise
//
//
// XXX iterator/generator as input:
// - do we unwind here or externally?
// ...feels like with the generator external unwinding is
// needed...
// XXX how do we handle errors/rejections???
__new__: function(_, list, handler){
// instance...
var promise