From ca4983c6305e5f14be4e66b1036aa3520c23bbe4 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Tue, 7 Feb 2023 19:34:07 +0300 Subject: [PATCH] reworked error handling in Promise's .iter(..)/.seqiter(..)/.. Signed-off-by: Alex A. Naanou --- Promise.js | 141 +++++++++++++++++++++++++++++---------------------- package.json | 2 +- test.js | 45 ++++++++++++++++ 3 files changed, 125 insertions(+), 63 deletions(-) diff --git a/Promise.js b/Promise.js index 6be8961..58eacf8 100644 --- a/Promise.js +++ b/Promise.js @@ -163,8 +163,8 @@ module.packed = return that.handle(packed, ...handlers) }) } var handleSTOP = function(err){ + stop = true if(err && err === Array.STOP){ - stop = true return [] } else if(err && err instanceof Array.STOP){ return err.value } @@ -174,66 +174,78 @@ module.packed = var map = Array.STOP ? 'smap' : 'map' - return packed - // NOTE: we do not need to rapack after this because the handlers - // will get the correct (unpacked) values and it's their - // responsibility to pack them if needed... - // NOTE: this removes the need to handle sub-arrays unless they are - // in a promise... - .flat() - [map]( - function(elem){ - return elem instanceof Promise ? - elem.then(function(elem){ - if(stop){ - return [] } - try{ - var has_promise = false - // NOTE: do the same thing handle(..) does - // but on a single level, without expanding - // arrays... - if(elem instanceof Array){ - var res = elem.map(function(elem){ - var res = elem instanceof Promise ? - elem.then(function(elem){ - try{ - return !stop ? - handler(elem) - : [] - } catch(err){ - return handleSTOP(err) } }) - : handler(elem) - has_promise = has_promise - || res instanceof Promise - return res }) - // non-arrays... - } else { - // NOTE: we are wrapping the result in an array to - // normalize it with the above... - res = [handler(elem)] - has_promise = has_promise - || res[0] instanceof Promise } + try{ + return packed + // NOTE: we do not need to rapack after this because the handlers + // will get the correct (unpacked) values and it's their + // responsibility to pack them if needed... + // NOTE: this removes the need to handle sub-arrays unless they are + // in a promise... + .flat() + [map]( + function(elem){ + return elem instanceof Promise ? + elem + .then(function(elem){ + if(stop){ + return [] } + try{ + var has_promise = false + // NOTE: do the same thing handle(..) does + // but on a single level, without expanding + // arrays... + if(elem instanceof Array){ + var res = elem + .map(function(elem){ + var res = elem instanceof Promise ? + elem.then(function(elem){ + try{ + return !stop ? + handler(elem) + : [] + }catch(err){ + return handleSTOP(err) } }) + : handler(elem) + has_promise = has_promise + || res instanceof Promise + return res }) + // non-arrays... + } else { + // NOTE: we are wrapping the result in an array to + // normalize it with the above... + res = [handler(elem)] + has_promise = has_promise + || res[0] instanceof Promise } - // compensate for the outer .flat()... - // NOTE: at this point res is always an array... - return has_promise ? - // NOTE: since we are already in a promise - // grouping things here is not a big - // deal, however this is needed to link - // nested promises with the containing - // promise... - Promise.all(res) - .then(function(res){ - return res.flat() }) - : res.flat() - } catch(err){ - return handleSTOP(err) } }) - : handler(elem) }, - // onerror... - function(err){ - stop = true - typeof(onerror) == 'function' - && onerror(err) }) }, + // compensate for the outer .flat()... + // NOTE: at this point res is always an array... + return has_promise ? + // NOTE: since we are already in a promise + // grouping things here is not a big + // deal, however this is needed to link + // nested promises with the containing + // promise... + Promise.all(res) + .then(function(res){ + return res.flat() }) + : res.flat() + } catch(err){ + return handleSTOP(err) } }) + // err... + .catch(function(err){ + stop = true + typeof(onerror) == 'function' + && onerror(err) + return [] }) + : handler(elem) }) + }catch(err){ + // err + if(err !== Array.STOP + && !(err instanceof Array.STOP) + && typeof(onerror) == 'function'){ + onerror(err) + return [] } + throw err } }, // // unpack() // -> @@ -822,12 +834,17 @@ object.Constructor('IterablePromise', Promise, { // populate new instance... if(promise){ + // handle onerror(..) + var handleError = function(err){ + onerror ? + promise.resolve(onerror(err)) + : promise.reject(err) } // handle/pack input data... if(handler != 'raw'){ //list = list instanceof IterablePromise ? list = list instanceof this.constructor ? - obj.__handle(list.__packed, handler, onerror) - : obj.__pack(list, handler, onerror) } + obj.__handle(list.__packed, handler, handleError) + : obj.__pack(list, handler, handleError) } Object.defineProperty(obj, '__packed', { value: list, enumerable: false, diff --git a/package.json b/package.json index 3411704..234796c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-types", - "version": "6.24.24", + "version": "6.25.0", "description": "Generic JavaScript types and type extensions...", "main": "main.js", "scripts": { diff --git a/test.js b/test.js index aef7222..fe8bb05 100755 --- a/test.js +++ b/test.js @@ -451,6 +451,51 @@ var cases = test.Cases({ '.seqiter(..): STOP(..): delayed') // XXX test .seqstartiter(..) + + + + // error... + for(var iter of ['iter', 'seqiter', 'seqstartiter']){ + assert( + await Promise[iter]([1,2,Promise.resolve(3),4,5], + function(e){ + if(e == 2){ + throw 'ERROR' } + return e }) + .catch(function(err){ + return 'done' }) + == 'done', + `.${iter}(..): .catch(..)`) + assert( + await Promise[iter]([1,2,Promise.resolve(3),4,5], + function(e){ + if(e == 2){ + throw 'ERROR' } + return e }, + function(err){ + return 'done' }) + == 'done', + `.${iter}(..): onerror(..)`) + assert( + await Promise[iter]([1,2,Promise.resolve(3),4,5], + function(e){ + if(e == 3){ + throw 'ERROR' } + return e }, + function(err){ + return 'done' }) + == 'done', + `.${iter}(..): edge onerror(..)`) + assert( + await Promise[iter]([1,2,Promise.resolve(3),4,5], + function(e){ + if(e == 4){ + throw 'ERROR' } + return e }, + function(err){ + return 'done' }) + == 'done', + `.${iter}(..): late onerror(..)`) } }, // Date.js