From 3fada85cd9142385c79209925e8a3b75dd113c76 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Thu, 2 Jun 2022 12:05:37 +0300 Subject: [PATCH] more work on iterable promises, still not ready... Signed-off-by: Alex A. Naanou --- Promise.js | 78 ++++++++++++++++++++++++++++++++++++++++-------------- README.md | 36 ++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/Promise.js b/Promise.js index 6f40eb1..b9dd3f5 100644 --- a/Promise.js +++ b/Promise.js @@ -114,6 +114,11 @@ object.Constructor('IterablePromise', Promise, { : [] }) }, // NOTE: this does not return an iterable promise as we can't know // what the user reduces to... + // NOTE: the items can be handled out of order because the nested + // promises can resolve in any order. + // XXX write how to go around this... + // NOTE: since order of execution can not be guaranteed there is no + // point in implementing .reduceRight(..) reduce: function(func, res){ return this.constructor(this.__list.flat(), function(e){ @@ -121,17 +126,6 @@ object.Constructor('IterablePromise', Promise, { return [] }) .then(function(){ return res }) }, - /*/ XXX this is wrong... - reduceRight: function(func, res){ - return this.constructor(this.__list.flat().reverse(), - function(e){ - res = func(res, e) - return [] }) - .then(function(){ - return res }) }, - // XXX this is wrong... - reverse: function(){ - return this.constructor(this.__list.flat().reverse()) }, flat: function(depth=1){ return this.constructor(this.__list.flat(), function(e){ @@ -142,11 +136,41 @@ object.Constructor('IterablePromise', Promise, { : depth != 0 ? e : [e] }) }, + // XXX REVERSE... + // XXX BUG: + // await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4]) + // .flat() + // -> [ 1, 'a', [ 'b', 'c' ], 2, 3, 4 ] + // await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4]) + // .flat() + // .reverse() + // -> [ 4, 2, 3, [ 'b', 'c', 'a' ], 1 ] + // ...should be: + // -> [ 4, 2, 3, [ 'b', 'c' ], 'a', 1 ] + // it's odd we are not seeing this in other places... + reverse: function(){ + return this.constructor(this.__list + .map(function(elems){ + return elems && elems.then ? + elems.then(function(res){ + return res + .reverse() + .flat() }) + : elems }) + .reverse() + .flat()) }, // compatibility with root promise... iter: function(){ - return this.constructor(this.__list.flat()) }, - //*/ + return this.constructor( + // clone and unwrap the .__list + this.__list + .map(function(elems){ + return elems && elems.then ? + elems.then(function(res){ + return res.flat() }) + : elems }) + .flat()) }, // XXX do we need these? // .pop() @@ -229,7 +253,13 @@ object.Constructor('IterablePromise', Promise, { // manually handle the stop... // - another issue here is that the stop would happen in order of // execution and not order of elements... + // XXX add support for list as a promise.... __new__: function(_, list, handler){ + // handle: IterablePromise(, ) + if(typeof(handler) == 'string'){ + mode = handler + handler = undefined } + // instance... var promise var obj = Reflect.construct( @@ -246,12 +276,16 @@ object.Constructor('IterablePromise', Promise, { if(promise){ // clone/normalize... - list = list - .map(function(e){ - return (e && e.then) ? - e.then(function(e){ - return [e] }) - : [e] }) + list = + list instanceof Promise ? + // XXX broken by reverse/flat but seems to work OK with others... + [list] + : list + .map(function(e){ + return (e && e.then) ? + e.then(function(e){ + return [e] }) + : [e] }) if(handler){ // NOTE: this is recursive to handle expanding nested promises... @@ -262,7 +296,7 @@ object.Constructor('IterablePromise', Promise, { return elems .map(handle) .flat() }) - : elem + : elem .map(handler) .flat() } @@ -483,6 +517,10 @@ var PromiseProtoMixin = module.PromiseProtoMixin = object.Mixin('PromiseProtoMixin', 'soft', { as: ProxyPromise, + + // XXX + iter: function(){ + return IterablePromise(this) }, }) PromiseProtoMixin(Promise.prototype) diff --git a/README.md b/README.md index 5160925..3972ab5 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ Library of JavaScript type extensions, types and utilities. - [`.then(..)`](#promise-coopthen) - [Promise iteration](#promise-iteration) - [`Promise.iter(..)` / `promise.IterablePromise(..)`](#promiseiter--promiseiterablepromise) + - [`.iter()`](#promiseiter) + - [`.iter()`](#promise-iteriter) - [`.map(..)` / `.filter(..)` / `.reduce(..)`](#promise-itermap--promise-iterfilter--promise-iterreduce) - [`.flat(..)`](#promise-iterflat) - [`.then(..)` / `.catch(..)` / `.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally) @@ -1452,8 +1454,8 @@ promise, and it is similar to a _generator_ in that it allows iteration over the contained values and chaining of operations but unlike `Promise.all(..)` this iteration occurs depth-first instead of breadth first. -Essentially one can think of _promise iterators_ vs. _generators_ as the former -being internally controlled and asynchronous while the later being externally +One can think of _promise iterators_ vs. _generators_ as the former being +internally controlled and asynchronous while the later being externally controlled and synchronous. Here is a traditional example using `Promise.all(..)`: @@ -1515,8 +1517,27 @@ XXX should we support infinite generators as input? #### `Promise.iter(..)` / `promise.IterablePromise(..)` Create an _iterable promise_ + ```bnf Promise.iter() +Promise.iter() + -> +``` + +#### `.iter()` + +```bnf +.iter() + -> +``` + + +#### `.iter()` + +Return a shallow copy of the current iterator. + +```bnf +.iter() -> ``` @@ -1545,7 +1566,7 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe ```bnf .reduce(, ) - -> + -> (, ) -> @@ -1558,6 +1579,15 @@ Note that these are different to `Array`'s equivalents in some details: this is because the index with _out-of-order_ and _depth-first_ execution the index is unknowable and the container is a promise/black-box. +This is especially critical for `.reduce(..)` as iteration in an order different +from the order of elements _can_ affect actual result if this is not expected. + +`.reduce(..)` is also a bit different here in that it will return a basic +`` object as we can't know what will it will reduce to. + +Note that since `.reduce(..)` order can not be guaranteed there is no point +in implementing `.reduceRigth(..)`. + #### `.flat(..)`