A general-purpose package for managing deferred or parallel tasks. Main features include:
- 100% compatible with
Promise
API. - Lazy evaluation
- Cancellation
- Pause/resume
- Initial delay
- Implemented on top of Javascript
Promise
implementation. Does not reinvent the wheel, helping to ensure consistent semantics.
- Awaitaable: You can
await
completion (or failure) of the combined set of tasks. - Background tasks: These do not directly contribute to the task result, but should complete before the task completes.
- Daemon Tasks: These do not directly contribute to the task result, but should be terminated when the task resolves.
- Filters strip down large data early, miimizing memory usage.
- _Data aggregation- (map/reduce). Reducers can often accumulate results in O(1) space.
- For example, average, RMS/quadratic mean, standard deviation (population & sample), bincount
- Task pools limit simultaneous execution, with its impact on memory usage and latency.
- Combined with an initial delay, can achieve a form of rate limiting.
- Very useful for web scraping applications.
These would produce an async generator. These would be useful for monitoring real-time event streams, calciulating things like moving averages.
Combined with Infinite tasks_, this would allow multiple consumers of an event stream
This package grew out of finding I needed something I'd written many times before in Javascript (and in other forms even before).
The scenario is this:
You have a computation task. You don't know if you will need the result. Typically, there will be many of these tasks, and you will only need a few of them.
You could return a function that you call when you need the result, and build adaptors for everything that uses them.
But your asynchronous task will return a Promise
, and your consumers of that are likely to expect a
Promise
. And you'd find yourself needing to cache the results, and to potentially notify multiple
awaiting consumers when results are available.
In short, we need something very much like a Promise
, but for a future result.
When you do this at scale, you find you need features like timeouts, cancellation, aggregation of results, resource management, memory optimization, etc.
Unfortunately, terminology has divered over the years between different communities. What python and Java call a "Future"
roughly corresponds to a Promise
+ cancellation. A "Task" in python is a scheduable coroutine that is also awaitable.
Although the core concepts overlap, it's best not to try to map the concepts between languages. There are differences due to python's convoluted async history, and there are differences due to how the runtimes operate.
The key terms here:
Promise
: always refers to a Javascript Promise- thenable: An object with a compliant
.then()
method. This includes instances ofPromise
,Future
, and predecessors to Javascript'sPromise
class. Future
: APromise
-like thenable that offers delayed/lazy execution, timeouts, and cancellation.- Task: A computation to be managed by a
Future
. This will typically be an async function returning aPromise
, but that is not a requirement. In the default case, they should take exactly zero arguments, or two arguments like he argment toPromise
.
The familiar Promise
API is here, including the static methods such as Promise.race
. A Future
implements .then()
, .catch()
, and .finally()
, and thus can be used
anywhere a Promise
can be.
The Future
API includes two key additions: .start()
and
.when()
.
Unlike a Promise
, a Future
does not begin
work until either Future
.start
() is called, or Future
.then
(), indicating a consumer for the information.
[Future``.when
()])api/classes/Future.html#when) is just like Future
.then
()
without the Future
.start
(). This is useful for passive consumers of the information.
For examplee:
return new Future(() => fetch(DATA_URL)).when(v => (console.log("data: ", v), v);
This also illustrates another feature: The [Future
)api/classes/Future.html#constructor) can accept
a function of zero arguments, and it will seamlessly be adapted to the (resolved, rejected) => void
pattern accepted by Promise
.