Options
All
  • Public
  • Public/Protected
  • All
Menu

Namespace signals

Provides utilities for synchronizing blocks of code.

// esm
import { signals } from '@paychex/core';

// cjs
const { signals } = require('@paychex/core');

// iife
const { signals } = window['@paychex/core'];

// amd
require(['@paychex/core'], function({ signals }) { ... });
define(['@paychex/core'], function({ signals }) { ... });

There are 4 types of signals provided in this module:

Manual Reset Signal

Think of the manual reset signal as a traffic light. While it is red, all cars are queued in the order they arrive. Once the light is signaled green, the cars can proceed in the order they arrived. And as long as the light remains green, any future cars can proceed.

Use cases:

  • wait for a router to bootstrap before enabling navigation
  • block all load operations until a save operation completes

Auto Reset Signal

The auto reset signal can be used to create a critical section -- i.e. a block of code that can only be executed by 1 caller at a time. Every other caller will be queued in the order they arrive, and the next caller in the queue will only be allowed to enter the critical section when the previous caller leaves the critical section.

Use cases:

  • ensure only 1 dialog is shown to the user at a time
  • queue router navigations while a navigation is in process
  • ensure a specific network call completes before being called again

Countdown Signal

A countdown signal allows you to queue callers until a certain number of operations have completed.

Use cases:

  • disable the UI until a group of downloads have finished
  • wait for a set of child components to load before stopping a timer

Semaphore

Think of a semaphore as a bouncer at a club who ensures that only a certain number of people are allowed in at one time. In other words, semaphores are used to control access to a limited pool of resources.

Use cases:

  • limit file uploads to a maximum of 5 at a time
  • limit in-progress data calls on a slow network

Index

Functions

  • Creates a signal that queues callers until signaled. Releases only 1 queued caller each time it is signaled, then automatically resets into a blocked state.

    The auto reset signal can be used to create a critical section -- i.e. a block of code that can only be executed by 1 caller at a time. Every other caller will be queued in the order they arrive, and the next caller in the queue will only be allowed to enter the critical section when the previous caller leaves the critical section.

    example
    import { fetch, createRequest } from '../path/to/datalayer';

    const signal = signals.autoReset(true); // start unblocked
    const operation = {
    method: 'POST',
    base: 'my-app',
    path: '/some/endpoint'
    };

    // ensure each network call completes
    // before the next call is performed:
    export async function networkCall() {
    await signal.ready(); // block other callers
    try {
    const data = { ... }; // payload to POST to the endpoint
    const request = createRequest(operation, null, data);
    const response = await fetch(request);
    return response.data;
    } finally {
    signal.set(); // unblock the next caller
    }
    }

    Parameters

    • signaled: boolean = false

    Returns AutoResetSignal

    A signal that releases 1 caller each time it is signaled.

  • Creates a signal that will queue callers until the counter reaches 0. At that point, all callers will be invoked in the order they were queued.

    example
    export function downloadAll(files = []) {
    const signal = signals.countdown(files.length);
    files.forEach(file =>
    download(file).finally(() =>
    signal.decrement()));
    return signal.ready();
    }
    example
    // progress blocking

    const counter = signals.countdown();

    export function addBlockingTask(task) {
    counter.increment();
    return Promise.resolve()
    .then(task)
    .finally(counter.decrement);
    }

    export function tasksCompleted() {
    return counter.ready();
    }

    Parameters

    • initialCount: number = 0

      The initial count of the signal. Must be a non-negative integer.

    Returns CountdownSignal

    Queues callers until the counter reaches 0.

  • Parameters

    • signaled: boolean = false

    Returns ManualResetSignal

  • semaphore(maxConcurrency?: number): Semaphore
  • Limits access to a pool of resources by restricting how many callers can run at a time. Any callers above the allowed amount will be queued until a spot is released.

    example
    import { fetch, createRequest } from '~/path/to/datalayer';
    import { tracker } from '~/path/to/tracker';

    const uploadSpots = signals.semaphore(5);

    const operation = {
    base: 'files',
    method: 'POST',
    path: '/save/:id'
    };

    export async function uploadFile(blob) {
    const data = new FormData();
    const params = { id: tracker.uuid() };
    data.append('file', blob, params.id);
    try {
    await uploadSpots.ready();
    await fetch(createRequest(operation, params, data));
    return params.id;
    } finally {
    uploadSpots.release(); // always release
    }
    }

    Parameters

    • maxConcurrency: number = 5

      The maximum number of parallel callers to allow.

    Returns Semaphore

    Limits access to a pool of resources by restricting how many callers can run at a time.