@reallyland/polling-observer

A new way of running polling function with observer pattern

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@reallyland/polling-observer
020.4.35 years ago5 years agoMinified + gzip package size for @reallyland/polling-observer in KB

Readme

@reallyland/polling-observer

A new way of running polling function with observer pattern




Buy Me A Coffee !tippin.metippin-me-badgetippin-me-url !Follow mefollow-me-badgefollow-me-url
!Versionversion-badgeversion-url !Node versionnode-version-badgenode-version-url !MIT Licensemit-license-badgemit-license-url
!Downloadsdownloads-badgedownloads-url !Total downloadstotal-downloads-badgedownloads-url !Packagephobiapackagephobia-badgepackagephobia-url !Bundlephobiabundlephobia-badgebundlephobia-url
!CircleCIcircleci-badgecircleci-url !Dependency Statusdaviddm-badgedaviddm-url !codecovcodecov-badgecodecov-url !Coverage Statuscoveralls-badgecoveralls-url
!codebeat badgecodebeat-badgecodebeat-url !Codacy Badgecodacy-badgecodacy-url !Code of Conductcoc-badgecoc-url
Like PerformanceObserver or any other observer APIs you could find in a browser, but this is for polling. Not only does it run polling with defined parameters but also collect polling metrics for each run until timeout or a defined condition fulfills.

Table of contents

- Node.js - Browser - Install - Usage
- [TypeScript or native ES Modules](#typescript-or-native-es-modules)
- [Node.js](#nodejs-1)
- Browser
- [ES Modules](#es-modules)
- [UMD](#umd)
- OnfinishFulfilled<T> - OnfinishRejected - PollingMeasure
- [Methods](#methods)
  - [PollingMeasure.toJSON()](#pollingmeasuretojson)
- PollingObserver<T>
- [Methods](#methods-1)
  - [PollingObserver.observe(callback[, options])](#pollingobserverobservecallback-options)
  - [PollingObserver.disconnect()](#pollingobserverdisconnect)
  - [PollingObserver.takeRecords()](#pollingobservertakerecords)
- [Event handler](#event-handler)
  - [PollingObserver.onfinish](#pollingobserveronfinish)

Pre-requisites

Node.js

Browser

Setup

Install

# Install via NPM
$ npm install --save @reallyland/polling-observer

Usage

Performance API is strictly required before running any polling. To ensure performance.now is available globally on Node.js, you can do:
/** Node.js */
import { performance } from 'perf_hooks';

global.performance = performance; // or globalThis.performance = performance;

TypeScript or native ES Modules

interface DataType {
  status: 'complete' | 'in-progress';
  items: Record<string, any>[];
}

import { PollingObserver } from '@reallyland/polling-observer';

const obs = new PollingObserver((data/** list, observer */) => {
  const { status, items } = data || {};
  const itemsLen = (items && items.length) || 0;

  /** Stop polling when any of the conditions fulfills */
  return 'complete' === status || itemsLen > 99;
});

obs.observe(
  async () => {
    /** Polling callback - fetch resources */
    const r = await fetch('https://example.com/api?key=123');
    const d = await r.json();

    return d;
  },
  /** Run polling (at least) every 2 seconds and timeout if it exceeds 30 seconds */
  {
    interval: 2e3,
    timeout: 30e3,
  }
);

/**
 * When polling finishes, it will either fulfill or reject depending on the status:
 * 
 * | Status  | Returns   |
 * | ------- | --------- |
 * | finish  | <value>   |
 * | timeout | <value>   |
 * | error   | <reason>  |
 * 
 */
obs.onfinish = (data, records/**, observer */) => {
  const { status, value, reason } = data || {};

  switch (status) {
    case 'error': {
      console.error(`Polling fails due to: `, reason);
      break;
    }
    case 'timeout': {
      console.log(`Polling timeouts after 30 seconds: `, value);
      break;
    }
    case 'finish':
    default: {
      console.log(`Polling finishes: `, value);
    }
  }

  console.log(`Formatted polling records: `, records.map(n => n.toJSON()));
  /**
   * [
   *   {
   *     duration: 100,
   *     entryType: 'polling-measure',
   *     name: 'polling:0',
   *     startTime: 100,
   *   },
   *   ...
   * ]
   */

  obs.disconnect(); /** Disconnect to clean up */
};

Node.js

const { PollingObserver } = require('@reallyland/polling-observer');

const obs = new PollingObserver((data/** entries, observer */) => {
  const { status, items } = data || {};
  const itemsLen = (items && items.length) || 0;

  /** Stop polling when any of the conditions fulfills */
  return 'complete' === status || itemsLen > 99;
});

obs.observe(
  async () => {
    /** Polling callback - fetch resources */
    const r = await fetch('https://example.com/api?key=123');
    const d = await r.json();

    return d;
  },
  /** Run polling (at least) every 2 seconds and timeout if it exceeds 30 seconds */
  {
    interval: 2e3,
    timeout: 30e3,
  }
);

/**
 * When polling finishes, it will either fulfill or reject depending on the status:
 * 
 * | Status  | Returns   |
 * | ------- | --------- |
 * | finish  | <value>   |
 * | timeout | <value>   |
 * | error   | <reason>  |
 * 
 */
obs.onfinish = (data, entries/**, observer */) => {
  const { status, value, reason } = data || {};

  switch (status) {
    case 'error': {
      console.error(`Polling fails due to: `, reason);
      break;
    }
    case 'timeout': {
      console.log(`Polling timeouts after 30 seconds: `, value);
      break;
    }
    case 'finish':
    default: {
      console.log(`Polling finishes: `, value);
    }
  }

  console.log(`Formatted polling entries: `, entries.map(n => n.toJSON()));
  /**
   * [
   *   {
   *     duration: 100,
   *     entryType: 'polling-measure',
   *     name: 'polling:0',
   *     startTime: 100,
   *   },
   *   ...
   * ]
   */

  obs.disconnect(); /** Disconnect to clean up */
};

Browser

ES Modules

<!doctype html>
<html>
  <head>
    <script type="module">
      import { PollingObserver } from 'https://unpkg.com/@reallyland/polling-observer@latest/dist/polling-observer.min.js';

      // --snip
    </script>
  </head>
</html>

UMD

<!doctype html>
<html>
  <head>
    <script src="https://unpkg.com/@reallyland/polling-observer@latest/dist/polling-observer.umd.min.js"></script>
    <script>
      var { PollingObserver } = window.PollingObserver;

      // --snip
    </script>
  </head>
</html>

Demo

Edit PollingObserver

API Reference

OnfinishFulfilled<T>

interface OnfinishFulfilled<T> {
  status: 'finish' | 'timeout';
  value: T;
}

OnfinishRejected

interface OnfinishRejected {
  status: 'error';
  reason: Error;
}

PollingMeasure

interface PollingMeasure {
  duration: number;
  entryType: 'polling-measure';
  name: string;
  startTime: number;
}

Methods

PollingMeasure.toJSON()

PollingObserver<T>

  • conditionCallback <Functionfunction-mdn-url> Condition callback to be executed in each polling and return the condition result in the type of boolean, e.g. return true to stop next poll.
- data <T> Polling data returned by callback in the type of T which defined in the PollingObserver.observe() method. - entries <Arrayarray-mdn-url<PollingMeasure>> A list of PollingMeasure objects. - observer <PollingObserver<T>> Created PollingObserver object. - returns: <booleanboolean-mdn-url> If true, the polling stops. Returning false will result in an infinite polling as the condition will never meet.

Methods

PollingObserver.observe(callback, options)
The method is used to initiate polling with a polling callback and optional configuration.
  • callback <Functionfunction-mdn-url> Callback to be executed in each polling and return the result so that it will be passed as the first argument in conditionCallback.
- returns: <T | Promisepromise-mdn-url<T>> Return polling result in the type of T or Promise<T> in each polling. - interval <numbernumber-mdn-url> Optional interval in milliseconds. This is the minimum delay before starting the next polling. - timeout <numbernumber-mdn-url> Optional timeout in milliseconds. Polling ends when it reaches the defined timeout even though the condition has not been met yet. As long as timeout is not a number or it has a value that is less than 1, it indicates an infinite polling. The polling needs to be stopped manually by calling PollingObserver.disconnect() method.
PollingObserver.disconnect()
Once a PollingObserver disconnects, the polling stops and all polling metrics will be cleared. Calling PollingObserver.takeRecords()
after the disconnection will always return an empty record.
A onfinish event handler can be used to retrieve polling records after a disconnection but it has to be attached before disconnecting the observer.
PollingObserver.takeRecords()
The method returns a list of PollingMeasure object containing the metrics of each polling.

Event handler

PollingObserver.onfinish
Note that no finish event fires when the polling finishes. So observer.addEventListener('finish', ...) will not work.
Event handler for when a polling finishes. When a polling finishes, it can either be fulfilled with a value or rejected with a reason. Any one of which contains a status field to tell the state of the finished polling.
When a polling fulfills, it returns an OnfinishFulfilled<T> object with status set to finish or timeout and a value in the type of T.
When a polling rejects, it returns an OnfinishRejected object with status set to error and a reason in the type of Errorerror-mdn-url.
| Status | Returns | | --------- | -------------- | | finish | <value> | | timeout | <value> | | error | <reason> |

deno

Coming soon.

License

MIT License © Rong Sen Ng (motss)