Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-10-08 13:04:49 +03:00
parent 7f183d3479
commit 4865d3ff71
6 changed files with 62 additions and 17 deletions

View File

@ -16,6 +16,7 @@ LOCAL_MODULES := \
EXT_MODULES := \
$(wildcard node_modules/pouchdb/dist/*) \
$(wildcard node_modules/jszip/dist/*) \
$(wildcard node_modules/idb-keyval/dist/*.js) \
$(wildcard node_modules/showdown/dist/*)
POUCH_DB := \

View File

@ -249,6 +249,15 @@ object.Constructor('IterablePromise', Promise, {
: (await Promise.all(list))
.flat() },
[Symbol.asyncIterator]: async function*(){
var list = this.__packed
if(list instanceof Promise){
yield this.__unpack(await list)
return }
for await(var elem of list){
yield* elem instanceof Array ?
elem
: [elem] } },
// iterator methods...
//

View File

@ -8,11 +8,29 @@
/*********************************************************************/
var object = require('ig-object')
var stoppable = require('ig-stoppable')
/*********************************************************************/
// Wrap .map(..) / .filter(..) / .reduce(..) / .. to support STOP...
//
// NOTE: internally these are implemented as for-of loops (./generator.js)
var stoppableSet = function(iter){
return function(func){
return new Set([...this][iter](...arguments)) } }
var stoppableValue = function(iter, no_return=false){
return function(func){
var res = [...this][iter](...arguments)
return no_return ?
undefined
: res } }
//---------------------------------------------------------------------
var SetProtoMixin =
module.SetProtoMixin =
object.Mixin('SetMixin', 'soft', {
@ -110,6 +128,12 @@ object.Mixin('SetMixin', 'soft', {
this.sort(order)
return removed },
filter: stoppableSet('filter'),
map: stoppableSet('map'),
reduce: stoppableValue('reduce'),
reduceRight: stoppableValue('reduceRight'),
forEach: stoppableValue('map', true),
})

View File

@ -189,11 +189,11 @@ var makeGenerator = function(name, pre){
].join('\n ') }, }) } }
// XXX do a better doc...
var makePromise = function(name){
var makeProxy = function(name){
return function(...args){
var that = this
return function(){
return that(...arguments)[name](func) } } }
return that(...arguments)[name](...args) } } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -267,9 +267,12 @@ object.Mixin('GeneratorMixin', 'soft', {
// promises...
//
then: makePromise('then'),
catch: makePromise('catch'),
finally: makePromise('finally'),
// NOTE: .then(..) and friends are intentionally not defined here to
// prevent control deadlocks when awaiting for a generator that
// expects manual unwinding e.g.:
// g = function*(){}
// await g // will hang waiting for g to resolve
unwind: makeProxy('unwind'),
// combinators...
//
@ -450,7 +453,8 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
// promises...
//
then: function(onresolve, onreject){
// NOTE: this will unwind the generator...
unwind: function(onresolve, onreject){
var that = this
var p = new Promise(
function(resolve){
@ -459,10 +463,12 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
p.then(...arguments)
: p
return p },
then: function(...args){
return this.unwind(...args) },
catch: function(func){
return this.then().catch(func) },
return this.unwind().catch(...arguments) },
finally: function(func){
return this.then().finally(func) },
return this.unwind.finally(...arguments) },
// combinators...
//
@ -531,22 +537,23 @@ object.Mixin('AsyncGeneratorProtoMixin', 'soft', {
//
// NOTE: this will unwind the generator...
// XXX create an iterator promise???
// XXX should we unwind???
then: function(resolve, reject){
unwind: function(onresolve, onreject){
var that = this
var p = new Promise(async function(_resolve, _reject){
var p = new Promise(async function(resolve){
var res = []
for await(var elem of that){
res.push(elem) }
_resolve(res) })
p = (resolve || reject) ?
resolve(res) })
p = (onresolve || onreject) ?
p.then(...arguments)
: p
return p },
then: function(...args){
return this.unwind(...args) },
catch: function(func){
return this.then().catch(func) },
finally: function(){
return this.then().finally(func) },
return this.unwind().catch(...arguments) },
finally: function(func){
return this.unwind.finally(...arguments) },
// XXX might be a good idea to use this approach above...
iter: stoppable(async function*(handler=undefined){

View File

@ -6,6 +6,7 @@
"dependencies": {
"@toast-ui/editor": "^3.2.0",
"glob": "*",
"idb-keyval": "^6.2.0",
"ig-actions": "*",
"ig-features": "*",
"ig-object": "*",

View File

@ -12,11 +12,14 @@
* - images
*
*
* XXX test: can we store the file handler with permissions in a ServiceWorker??
* XXX store: add an indexedDB backend -- save on serialization...
* - idb-keyval
* - native???
* XXX might be a good idea to wrap the wysiwig editor into a separate template
* and use it in the main edit template to make it user-selectable...
* XXX generalize html/dom api...
* ...see refresh() in pwiki2.html
* XXX npx http-server ... -- for testing file access...
* XXX test pouchdb latency at scale in browser...
* XXX BUG: for some reason deleting and refreshing takes ~2x as long as
* refreshing...