1 | <div align="center" style="text-align: center;">
|
2 | <h1 style="border-bottom: none;">async-poll</h1>
|
3 |
|
4 | <p>Advanced polling module with timeout and metrics collection</p>
|
5 | </div>
|
6 |
|
7 | <hr />
|
8 |
|
9 | <a href="https://www.buymeacoffee.com/RLmMhgXFb" target="_blank" rel="noopener noreferrer"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 20px !important;width: auto !important;" ></a>
|
10 | [![tippin.me][tippin-me-badge]][tippin-me-url]
|
11 | [![Follow me][follow-me-badge]][follow-me-url]
|
12 |
|
13 | [![Version][version-badge]][version-url]
|
14 | [![Node version][node-version-badge]][node-version-url]
|
15 | [![MIT License][mit-license-badge]][mit-license-url]
|
16 |
|
17 | [![Downloads][downloads-badge]][downloads-url]
|
18 | [![Total downloads][total-downloads-badge]][downloads-url]
|
19 | [![Packagephobia][packagephobia-badge]][packagephobia-url]
|
20 | [![Bundlephobia][bundlephobia-badge]][bundlephobia-url]
|
21 |
|
22 | [![CircleCI][circleci-badge]][circleci-url]
|
23 | [![Dependency Status][daviddm-badge]][daviddm-url]
|
24 | [![codecov][codecov-badge]][codecov-url]
|
25 | [![Coverage Status][coveralls-badge]][coveralls-url]
|
26 |
|
27 | [![codebeat badge][codebeat-badge]][codebeat-url]
|
28 | [![Codacy Badge][codacy-badge]][codacy-url]
|
29 | [![Code of Conduct][coc-badge]][coc-url]
|
30 |
|
31 | > Writing your own polling function can be difficult and hard to collect metrics about the polling. `asyncPoll` aims to solve those with modern JavaScript and advanced API. By leveraging `async...await`, asynchronous polling function has never been easier and [Performance Timing/ Timeline API][performance-timeline-api-url] is used to collect metrics about each polling in terms of the duration.
|
32 | >
|
33 | > 🛠Please check if `Performance Timing/ Timeline API` is supported on your browser or Node.js environment.
|
34 |
|
35 | ## Table of contents <!-- omit in toc -->
|
36 |
|
37 | - [Pre-requisites](#pre-requisites)
|
38 | - [Install](#install)
|
39 | - [Usage](#usage)
|
40 | - [TypeScript or native ES modules](#typescript-or-native-es-modules)
|
41 | - [Node.js](#nodejs)
|
42 | - [Browser](#browser)
|
43 | - [ES Modules](#es-modules)
|
44 | - [IIFE](#iife)
|
45 | - [Performance Timing/ Timeline API via `PerformanceObserver`](#performance-timing-timeline-api-via-performanceobserver)
|
46 | - [API Reference](#api-reference)
|
47 | - [AsyncPollOptions](#asyncpolloptions)
|
48 | - [asyncPoll\<T\>(fn, conditionFn[, options])](#asyncpolltfn-conditionfn-options)
|
49 | - [License](#license)
|
50 |
|
51 | ## Pre-requisites
|
52 |
|
53 | - [Node.js][nodejs-url] >= 8.9.0
|
54 | - [NPM][npm-url] >= 5.5.1 ([NPM][npm-url] comes with [Node.js][nodejs-url] so there is no need to install separately.)
|
55 |
|
56 | ## Install
|
57 |
|
58 | ```sh
|
59 | # Install via NPM
|
60 | $ npm install --save async-poll
|
61 | ```
|
62 |
|
63 | ## Usage
|
64 |
|
65 | ### TypeScript or native ES modules
|
66 |
|
67 | ```ts
|
68 | interface NewsData {
|
69 | data: {
|
70 | news: object[];
|
71 | status: number;
|
72 | };
|
73 | }
|
74 |
|
75 | import asyncPoll from 'async-poll';
|
76 |
|
77 | /** Fetch news from a mock URL */
|
78 | const fn = async () => fetch('https://example.com/api/news').then(r => r.json());
|
79 | /** Keep polling until the more than 100 `news` are received or `status` returns `complete` */
|
80 | const conditionFn = (d: NewsData) => d.data.news.length > 100 || d.data.status === 'complete';
|
81 | /** Poll every 2 seconds */
|
82 | const interval = 2e3;
|
83 | /** Timeout after 30 seconds and returns end result */
|
84 | const timeout = 30e3;
|
85 |
|
86 | asyncPoll<NewsData>(fn, conditionFn, { interval, timeout })
|
87 | .then(console.log)
|
88 | .catch(console.error);
|
89 | ```
|
90 |
|
91 | ### Node.js
|
92 |
|
93 | ```js
|
94 | const { asyncPoll } = require('async-poll');
|
95 |
|
96 | /** Fetch news from a mock URL */
|
97 | const fn = async () => fetch('https://example.com/api/news').then(r => r.json());
|
98 | /** Keep polling until the more than 100 `news` are received or `status` returns `complete` */
|
99 | const conditionFn = d => d.data.news.length > 100 || d.data.status === 'complete';
|
100 | /** Poll every 2 seconds */
|
101 | const interval = 2e3;
|
102 | /** Timeout after 30 seconds and returns end result */
|
103 | const timeout = 30e3;
|
104 |
|
105 | asyncPoll(fn, conditionFn, { interval, timeout })
|
106 | .then(console.log)
|
107 | .catch(console.error);
|
108 | ```
|
109 |
|
110 | ### Browser
|
111 |
|
112 | #### ES Modules
|
113 |
|
114 | ```html
|
115 | <script type="module">
|
116 | import { asyncPoll } from 'https://unpkg.com/async-poll@latest/dist/async-poll.js';
|
117 |
|
118 | /** Fetch news from a mock URL */
|
119 | const fn = async () => fetch('https://example.com/api/news').then(r => r.json());
|
120 | /** Keep polling until the more than 100 `news` are received or `status` returns `complete` */
|
121 | const conditionFn = d => d.data.news.length > 100 || d.data.status === 'complete';
|
122 | /** Poll every 2 seconds */
|
123 | const interval = 2e3;
|
124 | /** Timeout after 30 seconds and returns end result */
|
125 | const timeout = 30e3;
|
126 |
|
127 | asyncPoll(fn, conditionFn, { interval, timeout })
|
128 | .then(console.log)
|
129 | .catch(console.error);
|
130 | </script>
|
131 | ```
|
132 |
|
133 | #### IIFE
|
134 |
|
135 | ```html
|
136 | <script src="https://unpkg.com/async-poll@latest/dist/async-poll.iife.js"></script>
|
137 | <script>
|
138 | const { asyncPoll } = window.AsyncPoll;
|
139 |
|
140 | /** Fetch news from a mock URL */
|
141 | const fn = async () => fetch('https://example.com/api/news').then(r => r.json());
|
142 | /** Keep polling until the more than 100 `news` are received or `status` returns `complete` */
|
143 | const conditionFn = d => d.data.news.length > 100 || d.data.status === 'complete';
|
144 | /** Poll every 2 seconds */
|
145 | const interval = 2e3;
|
146 | /** Timeout after 30 seconds and returns end result */
|
147 | const timeout = 30e3;
|
148 |
|
149 | asyncPoll(fn, conditionFn, { interval, timeout })
|
150 | .then(console.log)
|
151 | .catch(console.error);
|
152 | </script>
|
153 | ```
|
154 |
|
155 | ### Performance Timing/ Timeline API via `PerformanceObserver`
|
156 |
|
157 | Performance timing data can be obtained via the experimental [Performance Tming API][performance-timing-api-url] that has been added as of [Node.js 8.5.0][nodejs-url] or [Performance Timeline API][performance-timeline-api-url] on browsers.
|
158 |
|
159 | ```ts
|
160 | /** For Node.js **only**, no import is required on browser. */
|
161 | import { PerformanceObserver } from 'perf_hooks';
|
162 |
|
163 | async function main() {
|
164 | let measurements: Record<string, unknown> = {};
|
165 | const perfObs = new PerformanceObserver((list) => {
|
166 | for (const n of list.getEntries()) {
|
167 | measurements[n.name] = n.duration;
|
168 | }
|
169 | });
|
170 | perfObs.observe({ entryTypes: ['measure'] });
|
171 | const d = await asyncPoll(fn, conditionFn, { interval, timeout });
|
172 | perObs.disconnect();
|
173 |
|
174 | return {
|
175 | data: d,
|
176 | measurements,
|
177 | };
|
178 | }
|
179 | ```
|
180 |
|
181 | ## API Reference
|
182 |
|
183 | ### AsyncPollOptions
|
184 |
|
185 | ```ts
|
186 | interface AsyncPollOptions {
|
187 | interval: number;
|
188 | timeout: number;
|
189 | }
|
190 | ```
|
191 |
|
192 | ### asyncPoll\<T\>(fn, conditionFn[, options])
|
193 |
|
194 | - `fn` <[Function][function-mdn-url]> Function to execute for each polling happens.
|
195 | - `conditionFn` <[Function][function-mdn-url]> Function to check the condition before a subsequent polling takes place. The function should return a boolean. If `true`, the polling stops and returns with a value in the type of `T`.
|
196 | - `options` <[AsyncPollOptions][asyncpolloptions-url]> Polling options.
|
197 | - `interval` <[number][number-mdn-url]> Polling interval.
|
198 | - `timeout` <[number][number-mdn-url]> Timeout.
|
199 | - returns: <[Promise][promise-mdn-url]<`T`>> Promise which resolves with a value in the type of `T`.
|
200 |
|
201 | ## License
|
202 |
|
203 | [MIT License](https://motss.mit-license.org/) © Rong Sen Ng (motss)
|
204 |
|
205 |
|
206 | [typescript-url]: https://github.com/Microsoft/TypeScript
|
207 | [nodejs-url]: https://nodejs.org
|
208 | [npm-url]: https://www.npmjs.com
|
209 | [node-releases-url]: https://nodejs.org/en/download/releases
|
210 | [performance-timing-api-url]: https://nodejs.org/api/perf_hooks.html
|
211 | [performance-timeline-api-url]: https://developer.mozilla.org/en-US/docs/Web/API/Performance
|
212 | [asyncpolloptions-url]: #asyncpolloptions
|
213 |
|
214 |
|
215 | [array-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
216 | [boolean-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
217 | [function-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
|
218 | [map-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
|
219 | [number-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
|
220 | [object-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
|
221 | [promise-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
222 | [regexp-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
|
223 | [set-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
|
224 | [string-mdn-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
|
225 |
|
226 |
|
227 | [tippin-me-badge]: https://badgen.net/badge/%E2%9A%A1%EF%B8%8Ftippin.me/@igarshmyb/F0918E
|
228 | [follow-me-badge]: https://flat.badgen.net/twitter/follow/igarshmyb?icon=twitter
|
229 |
|
230 | [version-badge]: https://flat.badgen.net/npm/v/async-poll/latest?icon=npm
|
231 | [node-version-badge]: https://flat.badgen.net/npm/node/async-poll
|
232 | [mit-license-badge]: https://flat.badgen.net/npm/license/async-poll
|
233 |
|
234 | [downloads-badge]: https://flat.badgen.net/npm/dm/async-poll
|
235 | [total-downloads-badge]: https://flat.badgen.net/npm/dt/async-poll?label=total%20downloads
|
236 | [packagephobia-badge]: https://flat.badgen.net/packagephobia/install/async-poll
|
237 | [bundlephobia-badge]: https://flat.badgen.net/bundlephobia/minzip/async-poll
|
238 |
|
239 | [circleci-badge]: https://flat.badgen.net/circleci/github/motss/async-poll?icon=circleci
|
240 | [daviddm-badge]: https://flat.badgen.net/david/dep/motss/async-poll
|
241 | [codecov-badge]: https://flat.badgen.net/codecov/c/github/motss/async-poll?label=codecov&icon=codecov
|
242 | [coveralls-badge]: https://flat.badgen.net/coveralls/c/github/motss/async-poll?label=coveralls
|
243 |
|
244 | [codebeat-badge]: https://codebeat.co/badges/56458b75-7d18-4a52-b3eb-b29f5367e244
|
245 | [codacy-badge]: https://api.codacy.com/project/badge/Grade/fdcab22d5b26401486e89d0ed1124171
|
246 | [coc-badge]: https://flat.badgen.net/badge/code%20of/conduct/pink
|
247 |
|
248 |
|
249 | [tippin-me-url]: https://tippin.me/@igarshmyb
|
250 | [follow-me-url]: https://twitter.com/igarshmyb?utm_source=github.com&utm_medium=referral&utm_content=motss/async-poll
|
251 |
|
252 | [version-url]: https://www.npmjs.com/package/async-poll
|
253 | [node-version-url]: https://nodejs.org/en/download
|
254 | [mit-license-url]: https://github.com/motss/async-poll/blob/master/LICENSE
|
255 |
|
256 | [downloads-url]: http://www.npmtrends.com/async-poll
|
257 | [packagephobia-url]: https://packagephobia.now.sh/result?p=async-poll
|
258 | [bundlephobia-url]: https://bundlephobia.com/result?p=async-poll
|
259 |
|
260 | [circleci-url]: https://circleci.com/gh/motss/async-poll/tree/master
|
261 | [daviddm-url]: https://david-dm.org/motss/async-poll
|
262 | [codecov-url]: https://codecov.io/gh/motss/async-poll
|
263 | [coveralls-url]: https://coveralls.io/github/motss/async-poll?branch=master
|
264 |
|
265 | [codebeat-url]: https://codebeat.co/projects/github-com-motss-async-poll-master
|
266 | [codacy-url]: https://www.codacy.com/app/motss/async-poll?utm_source=github.com&utm_medium=referral&utm_content=motss/async-poll&utm_campaign=Badge_Grade
|
267 | [coc-url]: https://github.com/motss/async-poll/blob/master/CODE_OF_CONDUCT.md
|