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.
This relies on Performance API which is available globally by default. For Node.js users, the API has been implemented and shipped as of Node.js v8.5.0. But it is not one of the global APIs, do the following before using the module:
const { performance } = require('perf_hooks');
global.performance = performance;interface DataType {
status: 'complete' | 'in-progress';
items: Record<string, any>[];
}
import { PollingObserver } from '@reallyland/node_mod/dist/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;
});
/**
* When polling finishes, it will either fulfill or reject depending on the status:
*
* | Status | Returns |
* | ------- | --------- |
* | finish | <value> |
* | timeout | <value> |
* | error | <reason> |
*
* Alternatively, `obs.addEventListener('finish', ...);` works too.
*/
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 */
};
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,
}
);interface OnfinishFulfilled<T> {
status: 'finish' | 'timeout';
value: T;
}interface OnfinishRejected {
status: 'error';
reason: Error;
}interface PollingMeasure {
duration: number;
entryType: 'polling-measure';
name: string;
startTime: number;
}duration<number> Duration of the polling takes in milliseconds.entryType<string> Entry type, defaults topolling-measure.name<string> Polling name in the format ofpolling:<index>where<index>starts from0and increments on each polling.startTime<string> Relative timestamp (in milliseconds ) indicates when the polling starts at.
- <Function> Returns a JSON representation of the polling object's properties.
conditionCallback<Function> Condition callback to be executed in each polling and return the condition result in the type of boolean, e.g. returntrueto stop next poll.data<T> Polling data returned bycallbackin the type ofTwhich defined in the PollingObserver.observe() method.entries<Array<PollingMeasure>> A list of PollingMeasure objects.observer<PollingObserver<T>> Created PollingObserver object.- returns: <boolean> If
true, the polling stops. Returningfalsewill result in an infinite polling as the condition will never meet.
- returns: <PollingObserver<
T>> PollingObserver object.
The method is used to initiate polling with a polling callback and optional configuration.
callback<Function> Callback to be executed in each polling and return the result so that it will be passed as the first argument inconditionCallback.- returns: <
T| Promise<T>> Return polling result in the type ofTorPromise<T>in each polling.
- returns: <
options<Object> Optional configuration to run the polling.interval<number> Optional interval in milliseconds. This is the minimum delay before starting the next polling.timeout<number> Optional timeout in milliseconds. Polling ends when it reaches the defined timeout even though the condition has not been met yet. As long astimeoutis 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.
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.
The method returns a list of PollingMeasure object containing the metrics of each polling.
- returns: <Array<PollingMeasure>> A list of PollingMeasure objects.
Alternatively, an event handler can be setup to listen for the finish event. See finish.
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.
onfinishCallback<Function> Callback to be executed when a polling finishes.-
data<OnfinishFulfilled<T>|OnfinishRejected> When a polling fulfills, it returns an OnfinishFulfilled<T> object withstatusset tofinishortimeoutand avaluein the type ofT. Whereas a polling rejects, it returns an OnfinishRejected object withstatusset toerrorand areasonin the type of Error.Status Returns finish<value> timeout<value> error<reason> -
entries<Array<PollingMeasure>> A list of PollingMeasure objects. -
observer<PollingObserver<T>> Created PollingObserver object.
-
finish event fires when a polling finishes.
const obs = new PollingObserver(/** --snip */);
// --snip
/** Same as using obs.onfinish = ... */
obs.addEventListener('finish', (ev: CustomEvent) => {
const {
detail: [
{ status, value/**, reason */ },
records,
observer,
],
} = ev;
// --snip
});MIT License © Rong Sen Ng