From 7d9b4943052962407adcd7b76fdf73d365f6e5bf Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Wed, 6 Jul 2022 15:54:03 +0300 Subject: [PATCH] added async function support + docs... Signed-off-by: Alex A. Naanou --- README.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- stoppable.js | 29 ++++++++++++---- 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e6a0f0a..bdabdde 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,23 @@ # stoppable.js Utility library implementing tooling to make stoppable functions... + +- [stoppable.js](#stoppablejs) + - [Install / import](#install--import) + - [Components](#components) + - [`stoppable(..)`](#stoppable) + - [`stoppable.STOP / stoppable.STOP(..)`](#stoppablestop--stoppablestop) + - [Examples](#examples) + - [Function](#function) + - [Async function](#async-function) + - [Generator](#generator) + - [Async generator](#async-generator) + - [License](#license) + + + +## Install / import + ```shell $ npm install --save ig-stoppable ``` @@ -10,6 +27,52 @@ var stoppable = require('ig-stoppable') ``` +## Components + +### `stoppable(..)` + +Create a wrapper for the input function/generator. + +```bnf +stoppable() + -> + +stoppable() + -> + +stoppable() + -> + +stoppable() + -> +``` + + +### `stoppable.STOP / stoppable.STOP(..)` + +A special object/constructor that can be either returned/thrown _as-is_ or +used to create an _instance_ to be returned thrown. + +```bnf +stoppable.STOP + +stoppable.STOP() +stoppable.STOP() + -> +``` + +This will get intercepted by `stoppable(..)` and appropriately handled merging +it into the return/yield value and stopping the function/iterator. + +`` can contain a value that will get handled by `stoppable(..)` (default: `undefined`). + + +## Examples + + + +### Function + ```javascript var func = stoppable(function(){ // ... @@ -22,6 +85,23 @@ var func = stoppable(function(){ var value = func() // -> 'something' ``` + +### Async function +```javascript +var func = stoppable(async function(){ + // ... + + throw stoppable.STOP('something') + + // ... +}) + +var value = await func() // -> 'something' +``` + + +### Generator + ```javascript var gen = stoppable(function*(){ // ... @@ -34,6 +114,9 @@ var gen = stoppable(function*(){ var value = [...gen()] // -> ['somthing'] ``` + +### Async generator + ```javascript var agen = stoppable(async function*(){ // ... @@ -44,4 +127,15 @@ var agen = stoppable(async function*(){ }) var value = awat agen() // -> ['something'] -``` \ No newline at end of file +``` + + +## License + +[BSD 3-Clause License](./LICENSE) + +Copyright (c) 2022-, Alex A. Naanou, +All rights reserved. + + + diff --git a/package.json b/package.json index bfb8aa0..3183eae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-stoppable", - "version": "2.0.0", + "version": "2.0.1", "description": "Utility library implementing tooling to make stoppable functions...", "main": "stoppable.js", "scripts": { diff --git a/stoppable.js b/stoppable.js index 0a955a7..4e5abec 100644 --- a/stoppable.js +++ b/stoppable.js @@ -18,6 +18,9 @@ //--------------------------------------------------------------------- // helpers... +var AsyncFunction = + (async function(){}).constructor + var Generator = (function*(){}).constructor @@ -66,10 +69,9 @@ var AsyncGenerator = module = function(func){ return Object.assign( + // NOTE: the below implementations are almost the same, the main + // differences being the respective generator/async mechanics... func instanceof Generator ? - // NOTE: the only difference between Generator/AsyncGenerator - // versions of this is the async keyword -- keep them - // in sync... function*(){ try{ for(var res of func.call(this, ...arguments)){ @@ -87,12 +89,9 @@ function(func){ return } throw err } } : func instanceof AsyncGenerator ? - // NOTE: the only difference between Generator/AsyncGenerator - // versions of this is the async keyword -- keep them - // in sync... async function*(){ try{ - for(var res of func.call(this, ...arguments)){ + for await(var res of func.call(this, ...arguments)){ if(res === module.STOP){ return } if(res instanceof module.STOP){ @@ -106,6 +105,22 @@ function(func){ yield err.value return } throw err } } + : func instanceof AsyncFunction ? + async function(){ + try{ + var res = await func.call(this, ...arguments) + // NOTE: this is here for uniformity... + if(res === module.STOP){ + return } + if(res instanceof module.STOP){ + return res.value } + return res + } catch(err){ + if(err === module.STOP){ + return + } else if(err instanceof module.STOP){ + return err.value } + throw err } } : function(){ try{ var res = func.call(this, ...arguments)