1.0.2 • Published 4 months ago

@figliolia/task-queue v1.0.2

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

Task Queue

Task prioritization and scheduling made easy!

Getting Started

Installation

npm install --save @figliolia/task-queue
# or
yarn add @figliolia/task-queue

Basic Usage

Scheduling Tasks using Prioritized Execution

import { TaskQueue } from "@figliolia/task-queue";

const TQ = new TaskQueue({ priorities: 4 });
// This TaskQueue will have 4 priority levels for
// registering tasks

const task1 = () => {};
const task2 = () => {};
const task3 = () => {};
const task4 = () => {};

TQ.registerTask(task1, 4); // Priority 4
TQ.registerTask(task2, 3); // Priority 3
TQ.registerTask(task3, 2); // Priority 2
TQ.registerTask(task4, 1); // Priority 1

const cancelFN = TQ.executeAll();
// The execution order => task4, task3, task2, task1

// Calling cancelFN() will cancel task execution at any point

Scheduling Tasks using deferrals

import { TaskQueue } from "@figliolia/task-queue";

const TQ = new TaskQueue();

const cancelFN = TQ.deferTask(() => {
  // This task will execute after 1000ms
  // and won't leak memory if canceled
}, 1000);

// Optionally calling `cancelFN()` will prevent the
// task from being executed

API

Task Queue

registerTask(task: Task, priority: number): CancelFN

Registers a function to execute at a certain priority level. Returns a cancel function that, if called, will remove the task from the queue

import { TaskQueue } from "@figliolia/task-queue";

const N = 3;

const TQ = TaskQueue({ priorities: N });

const cancelFN = TQ.registerTask(() => {}, 1)
deferTask(task: Task, delay: number): CancelFN

Registers a task to execute after a specified delay. Returns a cancel function that, if called, will remove the task from the queue

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue();

const cancelFN = TQ.deferTask(() => {}, 1000);
executeAll(onComplete?: Task, taskSeparation?: number): CancelFN

Executes all prioritized tasks registered using registerTask(). Tasks are executed based on the priority levels that they were registered with and dispersed along the call stack using the taskSeparation.

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue({ priorities: 3 });

// Register any number of tasks
TQ.registerTask(() => {}, 1);
TQ.registerTask(() => {}, 2);
TQ.registerTask(() => {}, 3);

const cancelFN = TQ.executeAll(() => {
  console.log('Complete!');
}, 35 /* task separation */);

The taskSeparation parameter can be used to disperse registered tasks along the call stack. taskSeparation = the number of milliseconds to elapse between tasks. It's set to 0 by default. This is designed to prevent the creation of long blocking tasks when the Task Queue has several entries.

Invoking the returned cancel function will pause the execution of the remaining tasks in the queue until executeAll() is called again.

executeTasksWithPriority(): CancelFN

Executes all tasks registered at a specified priority level. Returns a cancel function

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue({ priorities: 3 });
// Register any number of tasks

const cancelFN = TQ.executeTasksWithPriority(
  1, // Priority 
  0, // Task Separation MS
  () => { // On complete function
  console.log("Complete!");
});
// Executes all tasks registered with priority level 1

Calling the returned cancel function will pause the execution of tasks.

Using executeTasksWithPriority() can allow developers to organize tasks based on arbitrary means and identify them using their priority. This can be useful if managing the execution of registered tasks based on arbitrary categorization. Let's look at an example using application routing:

import { TaskQueue } from "@figliolia/task-queue";

const TQ = new TaskQueue({ priorities: 3 });

// Let's map our application routes to a priority level
enum RouteMap {
  "home" = 1,
  "about" = 2,
  "profile" = 3
}

// Next lets register a data loading task for
// each route
TQ.registerTask(() => {
  // Tasks to execute when navigating to home
  void fetchGreeting();
}, RouteMap.home);

TQ.registerTask(() => {
  // Tasks to execute when navigating to about
  void fetchUserData();
}, RouteMap.about);

TQ.registerTask(() => {
  // Tasks to execute when navigating to profile
  void fetchProfile();
}, RouteMap.profile);

// Listen for routing changes using hashchange or pushstate
window.addEventListener("hashchange", () => {
  const nextRoute = window.location.hash.slice(1);
  if(nextRoute in RouteMap) {
    // Execute data loader for matched routes!
    TQ.executeTasksWithPriority(routeMap[nextRoute]);
  }
});

In the above example, the TaskQueue's priority levels are used for categorizing data preloading tasks based on the route they correspond with. When the browser routes to a supported route found in the routeMap, the tasks corresponding with the route are executed as early as possible.

clearPendingTasks(): void

Removes all pending tasks from the task TaskQueue. This includes both prioritized tasks registered using TaskQueue.registerTask() and deferred tasks registered using TaskQueue.deferTask()

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue({ priorities: 3 });

TQ.registerTask(() => {}, 1);
TQ.registerTask(() => {}, 2);
TQ.registerTask(() => {}, 3);
TQ.deferTask(() => {}, 1000);

TQ.clearPendingTasks(); 
// Resets the Queue removing all registered tasks
clearDeferredTasks(): void

Removes all pending tasks registered using TaskQueue.deferTask(). These tasks are released, cancelled and forgotten by the TaskQueue

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue();

TQ.deferTask(() => {}, 1000);
TQ.deferTask(() => {}, 2000);
TQ.deferTask(() => {}, 3000);

TQ.clearDeferredTasks(); 
// Cancels all currently pending deferred tasks
getCancelFN(): CancelFN | void

Returns the current cancel token if the TaskQueue is executing or undefined if the TaskQueue is idol.

import { TaskQueue } from "@figliolia/task-queue";

const TQ = TaskQueue({ priorities: 3 });

// Register any number of tasks
TQ.registerTask(() => {}, 1);
TQ.registerTask(() => {}, 2);
TQ.registerTask(() => {}, 3);

TQ.executeAll();

const cancel = TQ.getCancelFN(); 
// Returns a CancelFN during execution
cancel && cancel()

Advanced Usage

Using autoRun

The autoRun option is designed to make your TaskQueues run at all times. This option will cause registered tasks to auto-execute as soon as they're enqueued. Tasks will continue to execute at their appropriate priority levels, but allow lower priority tasks to execute immediately if the Queue is empty!

const TQ = new TaskQueue({ 
  priorities: 3, 
  autoRun: true,
  taskSeparation: 10
});

const task1 = () => {};
const task2 = () => {};
const task3 = () => {}

TQ.registerTask(task3, 3);
TQ.registerTask(task2, 2);
TQ.registerTask(task1, 1);

// The above tasks will execute without calling `TQ.executeAll()`

// The execution order will be task1 => task2 => task3 with 10ms 
// elapsing between each task

// To cancel task execution at any point
const cancel = TQ.getCancelFN();
cancel && cancel();

// To begin execution again
TQ.executeAll()

Using the autoRun option is great prioritizing the execution of startup tasks in complex frontend apps or responsibly managing request handling on the server