time-queues
v1.0.5
Published
Time queues to organize multitasking and scheduled tasks.
Downloads
19
Readme
time-queues
time-queues
is an efficient library for organizing asynchronous multitasking and scheduled tasks.
It can be used in a browser and in server-side environments like Node
, Deno
and Bun
.
It depends only on list-toolkit, which is a no-dependency library for efficient task queues.
The following features are provided:
- All environments:
- Scheduler: a
MinHeap
-based task queue that schedules time-based tasks in the future.- repeat(): a function that creates a repeatable task.
- defer(): a function that executes a task at a later time in the next tick.
- Scheduler: a
- Browsers:
- Efficient multitasking:
- IdleQueue: a task queue that executes tasks in the next idle period.
- Based on requestIdleCallback().
- defer(): a function that executes a task at a later time in the next idle period.
- FrameQueue: a task queue that executes tasks in the next frame.
- Based on requestAnimationFrame().
- IdleQueue: a task queue that executes tasks in the next idle period.
- Page state management:
- PageWatcher: a task queue that executes tasks when the page state changes.
- watchStates(): a helper that pauses and resumes queues when the page state changes.
- whenDomLoaded(): a helper that executes tasks when the DOM is loaded.
- whenLoaded(): a helper that executes tasks when the page is loaded.
- PageWatcher: a task queue that executes tasks when the page state changes.
- Efficient multitasking:
Internally it uses List Toolkit and leverages the following browser APIs:
- requestIdleCallback()
- requestAnimationFrame()
- queueMicrotask()
- setTimeout()
- Various events and properties.
There are many articles on the subject that detail how to leverage the APIs writing efficient applications. Some of them are:
This package eliminates the need to write code that you'll write anyway following best practices.
Installation
npm install time-queues
If you want to check out the source code, you can use the following command:
git clone https://github.com/uhop/time-queues.git
cd time-queues
npm install
Don't forget to look at a test web application that uses the library. For that you should start a server:
npm start
And navigate to http://localhost:3000/tests/web/ — don't forget to open the console and play around: switch tabs, make other window active, navigate away and come back, and so on. See how queues work in tests/web/test.js.
Usage
The full documentation is available in the project's wiki. Below is a cheat sheet of the API.
ListQueue
ListQueue
is a list-based task queue that executes tasks in the order they were added.
It serves as a base class for other task queues. The following methods are available:
| Method | Description |
|:---|:---|
| ListQueue(paused)
| Create a new list queue (paused optionally). |
| isEmpty
| Check if the list queue is empty. |
| pause()
| Pause the list queue. |
| resume()
| Resume the list queue. |
| enqueue(fn)
| Schedule a function to be executed. Returns the task. |
| dequeue(task)
| Remove a task from the list queue. |
| clear()
| Remove all tasks from the list queue. |
Subclasses should implement startQueue()
.
Scheduler
Scheduler
is a MinHeap
-based task queue that schedules time-based tasks in the future.
It can used to run periodic updates or one-time events.
Scheduler
is not based on ListQueue
, but implements its API.
The following additional methods are available:
| Method | Description |
|:---|:---|
| Scheduler(paused)
| Create a new scheduler (paused optionally). |
| nextTime
| Get the next scheduled time or 'Infinityif the scheduler is empty. |
|
enqueue(fn, time)| Schedule a function to be executed at a later time. Returns the task.
time` can be a date or a number in milliseconds from now. |
Scheduled functions are called once with the following arguments:
fn(task, scheduler)
, where:fn
— the scheduled function.task
— the task object that corresponds to the scheduled function.scheduler
— the scheduler object.
The return value is ignored.
The module provides a singleton ready to be used:
import scheduler, {repeat} from 'time-queues/Scheduler.js';
// schedule a task
const task = scheduler.enqueue(() => console.log('The first task'), 1000);
// run a task every second
const hello = () => {
console.log('Hello, world!');
scheduler.enqueue(hello, 1000);
};
scheduler.enqueue(hello, 1000);
// pause the scheduler
scheduler.pause();
// remove the first task
scheduler.dequeue(task);
// remove all tasks
scheduler.clear();
repeat()
The module provides a helper function repeat()
that creates a repeatable task:
repeat(fn, interval)
, where:fn
— the scheduled function.interval
— the interval in milliseconds. If not specified the corresponding task delay is used.
We can rewrite the above example using repeat()
:
// run a task every second
scheduler.enqueue(repeat(() => console.log('Hello, world!'), 1000));
defer()
defer(fn)
is a function that executes an argument function at a later time in the next tick.
Deferred functions are called with no arguments. The return value is ignored.
import defer from 'time-queues/defer.js';
// run a task in the next tick
defer(() => console.log('Goodbye, world!'));
// run code now
console.log('Hello, world!');
IdleQueue
IdleQueue
is a task queue that executes tasks in the next idle period. It implements ListQueue
and is based on requestIdleCallback().
Efficient web applications should use IdleQueue
to schedule computations required to prepare data and
even create necessary DOM elements.
See Background Tasks API for more information.
Queued functions are called once with the following arguments:
fn(deadline, task, idleQueue)
, where:fn
— the scheduled function.deadline
— the deadline object. See requestIdleCallback() for more information.task
— the task object that corresponds to the scheduled function.idleQueue
— the idle queue object.
The return value is ignored.
The module provides a singleton ready to be used:
import idleQueue from 'time-queues/IdleQueue.js';
import frameQueue from 'time-queues/FrameQueue.js';
idleQueue.enqueue(() => {
// prepare our data and generate DOM
const div = document.createElement('div');
div.appendChild(document.createTextNode('Hello, world!'));
// now update the DOM in the next frame
frameQueue.enqueue(() => document.body.appendChild(div));
});
FrameQueue
FrameQueue
is a task queue that executes tasks in the next frame. It implements ListQueue
and is based on requestAnimationFrame().
Efficient web applications should use FrameQueue
to schedule DOM updates.
See Background Tasks API for more information.
Queued functions are called once with the following arguments:
fn(timeStamp, task, frameQueue)
, where:fn
— the scheduled function.timeStamp
— the timestamp object. See requestAnimationFrame() for more information.task
— the task object that corresponds to the scheduled function.frameQueue
— the frame queue object.
The return value is ignored.
The module provides a singleton ready to be used. See the code snippet IdleQueue
above for more information.
PageWatcher
PageWatcher
is a task queue that executes tasks when the page state changes. It is based on Page Visibility API.
You can find more information in Page Lifecycle API.
Efficient web applications should use PageWatcher
to watch for page visibility changes and react accordingly, for example, by suspending updates in the hidden state.
PageWatcher
implements ListQueue
. The following additional/changed methods are available:
| Method | Description |
|:---|:---|
| PageWatcher(started)
| Create a new page watcher (started optionally). |
| currentState
| Get the current page state (see below). |
| enqueue(fn, initialize)
| Schedule a function to be executed. Returns the task. If initialize
is truthy, the function will be queued and called immediately with the current state. |
A page state can be one of the following strings:
active
— the page is a current window, it is visible and the user can interact with it.passive
— the page is not a current window, it is visible, but the user cannot interact with it.hidden
— the page is not visible.frozen
— the page is suspended, no timers nor fetch callbacks can be executed.terminated
— the page is terminated, no new tasks can be started.
Queued functions are called on every state change with the following arguments:
fn(state, previousState, task, pageWatcher)
, where:- 'fn` — the scheduled function.
state
— the new page state.previousState
— the previous page state.task
— the task object that corresponds to the scheduled function.pageWatcher
— the page watcher object.
The return value is ignored.
The module provides a singleton ready to be used.
import pageWatcher from 'time-queues/PageWatcher.js';
pageWatcher.enqueue(state => console.log('state:', state), true);
watchStates()
watchStates()
is a helper that pauses and resumes queues when the page state changes.
It can be added to a PageWatcher
object controlling a Scheduler
object or any other queue
to pause it depending on a page state.
The function signature is:
watchStates(queue, resumeStatesList = ['active'])
, where:queue
— the queue object to be controlled.resumeStatesList
— the iterable of page states toresume()
. All other states will pause the queue. Defaults to 'active'.
The return value is a function that is suitable for PageWatcher.enqueue()
.
import pageWatcher, {watchStates} from 'time-queues/PageWatcher.js';
import scheduler from 'time-queues/Scheduler.js';
// do not process time-based tasks when the page is not visible
pageWatcher.enqueue(watchStates(scheduler, ['active', 'passive']), true);
whenDomLoaded()
whenDomLoaded()
is a helper that executes a function when the DOM is loaded.
If the DOM is already loaded, the function will be executed with queueMicrotask()
.
Otherwise it'll be queued and executed when the DOM is loaded.
See DOMContentLoaded for more information.
The function signature is:
whenDomLoaded(fn)
, where:fn
— the function to be executed when the DOM is loaded.
It will be called with no arguments. The return value is ignored.
import whenDomLoaded from 'time-queues/whenDomLoaded.js';
whenDomLoaded(() => console.log('The DOM is loaded'));
whenLoaded()
whenLoaded()
is a helper that executes a function when the page is fully loaded.
If the page is already loaded, the function will be executed with queueMicrotask()
.
Otherwise it'll be queued and executed when the page is loaded.
See load for more information.
The function signature is:
whenLoaded(fn)
, where:fn
— the function to be executed when the page is loaded.
It will be called with no arguments. The return value is ignored.
import whenLoaded from 'time-queues/whenLoaded.js';
whenLoaded(() => console.log('The page is loaded'));
License
This project is licensed under the BSD-3-Clause License.
Release History
- 1.0.5 Technical release: updated deps, more tests.
- 1.0.4 Bug fixes and code simplifications.
- 1.0.3 Updated deps (
list-toolkit
) to fix a minor bug. - 1.0.2 Updated deps (
list-toolkit
). - 1.0.1 Minor update in README. No need to upgrade.
- 1.0.0 Initial release.