@bugtamer/async-status
Version:
Asynchronous process status helper.
264 lines (201 loc) • 8.68 kB
Markdown
# AsyncStatus JS
Manages the status of an async process.
- Built-in TypeScript declarations.
- Built-in Javascript / TypeScript map declarations.
- Comprehensive unit testing.
- [Available at npmjs.com](https://www.npmjs.com/package/@bugtamer/async-status)
- [Source Code](https://github.com/bugtamer/async-status-js)
## Table Of Content
- [Installation](#installation)
- [As project dependency](#as-project-dependency)
- [As script dependency](#as-script-dependency)
- [Basic usage snippets](#basic-usage-snippets)
- [async / await](#async-await)
- [Observable](#observable)
- [Status management / Class interface](#status-management-class-interface)
- [Use](#use)
- [Check attempt stats](#check-attempt-stats)
- [Check current state](#check-current-state)
- [Check last outcome state](#check-last-outcome-state)
- [Measure the time](#measure-the-time)
- [Final notes](#final-notes)
- [Examples](#examples)
## Installation
### As project dependency
`npm i @bugtamer/async-status`
[Available at npmjs.com](https://www.npmjs.com/package/@bugtamer/async-status)
### As script dependency
['require' demo example](https://runkit.com/bugtamer/async-status)
```javascript
const bugtamer = require("@bugtamer/async-status")
const dataAsyncStatus = new bugtamer.AsyncStatus();
```
or
```javascript
const bugtamer = require("@bugtamer/async-status/lib/async-status")
const dataAsyncStatus = new bugtamer.AsyncStatus();
```
['import' demo example](https://github.com/bugtamer/ng-async-status-example)
```javascript
import { AsyncStatus } from '@bugtamer/async-status/lib/async-status';
const dataAsyncStatus = new AsyncStatus();
```
## Basic usage snippets
### async / await
```javascript
dataAsyncStatus.start();
try {
data = await fetchData();
dataAsyncStatus.end();
} catch (error) {
dataAsyncStatus.abort();
}
```
### Observable
```javascript
dataAsyncStatus.start();
const subscription = fetchData().subscribe(
response => {
data = response;
dataAsyncStatus.end();
},
error => {
dataAsyncStatus.abort();
}
);
```
## Status management / Class interface
### Use
| Current State | Method called / Sentence | Outcome |
| ------------- | ------------------------ | -------------- |
| | `new AsyncStatus()` | idle state |
| idle | `start()` | ongoing state |
| ongoing | `end()` | idle state |
| ongoing | `abort()` | idle state |
| ongoing | `start()` | Throw an error |
| idle | `end()` | Throw an error |
| idle | `abort()` | Throw an error |
Do not try to manage these errors, just fix your code.
They point out that some method should never have called.
### Check attempt stats
| Sentence | Description |
|---------------------------------------|------------------------------------------|
| `dataAsyncStatus.attempts` | returns the number of calls to `start()` |
| `dataAsyncStatus.successfulAttempts` | returns the number of calls to `end()` |
| `dataAsyncStatus.failedAttempts` | returns the number of calls to `abort()` |
| `dataAsyncStatus.resetAttemptStats()` | all previous counters are set to 0 |
### Check current state
In this section we understand by _call_ a call to any of the following methods: `start()`, `end()` or `abort()`.
#### Idle State
There is no process activity.
| `dataAsyncStatus.isIdle` | Returns |
|-----------------------------------------------------------------------------|---------|
| When `start()` was never executed or the last call was `end()` or `abort()` | `true` |
| In any other case | `false` |
#### Ongoing state
There is a process in progress.
| `dataAsyncStatus.isOngoing` | Returns |
|---------------------------------------------------------------------------------------------------|---------|
| When the last call was `start()` and therefore neither `end()` nor `abort()` have been called yet | `true` |
| In any other case | `false` |
### Check last outcome state
In this section we understand by _call_ a call to any of the following methods: `start()`, `end()` or `abort()`.
#### A successful outcome
| `dataAsyncStatus.wasSuccessful` | Returns |
|-----------------------------------------|---------|
| When `end()` was the last method called | `true` |
| In any other case | `false` |
#### A failed outcome
| `dataAsyncStatus.wasFailed` | Returns |
|-------------------------------------------|---------|
| When `abort()` was the last method called | `true` |
| In any other case | `false` |
### Measure the time
In milliseconds (ms):
| `dataAsyncStatus.elapsedTime` | Returns |
|-------------------------------------------------------------------------------|------------------------------------------------------------------|
| when `start()` was never called | `AsyncStatus.UNDEFINED_TIME` (`-1`) |
| when `start()` was called but `end()` or `abort()` has not yet been called | Time elapsed since the call to `start()` to current time |
| when `start()` was called and eventually `end()` or `abort()` was also called | Elapsed time from call to `start()` to `end()` or `abort()` call |
## Final notes
- Using a single instance of `AsyncStatus` to control multiple independent asynchronous processes that overlap in time could lead to erratic behavior in your program.
- `start()` throws an error when is called more than `Number.MAX_SAFE_INTEGER` times (although is nearly unreachable).
## Examples
- [Angular demo example](https://bugtamer.github.io/ng-async-status-example/)
- [Check out](https://runkit.com/bugtamer/async-status) the following example at RunKit:
```javascript
// const bugtamer = require("@bugtamer/async-status/lib/async-status")
const bugtamer = require("@bugtamer/async-status")
function showStats(asyncStatus, message) {
console.log(message)
console.log(` - Attempts: ${asyncStatus.attempts}`)
console.log(` - successful: ${asyncStatus.successfulAttempts}`)
console.log(` - failed: ${asyncStatus.failedAttempts}`)
console.log(` - State:`)
console.log(` - idle: ${asyncStatus.isIdle}`)
console.log(` - ongoing: ${asyncStatus.isOngoing}`)
console.log(` - Outcome:`)
console.log(` - successful: ${asyncStatus.wasSuccessful}`)
console.log(` - failed: ${asyncStatus.wasFailed}`)
console.log(` - Time elapsed: ${asyncStatus.elapsedTime} ms`)
}
// Let's show where the Internation Space Station currently is.
console.log("Let's see where the ISS is with Node " + process.version);
// We can use any package from NPM since they are all built in.
var getJSON = require("async-get-json");
const status = new bugtamer.AsyncStatus();
showStats(status, 'new AsyncStatus()')
status.start()
showStats(status, 'start()')
const url = "http://api.open-notify.org/iss-now.json"; // change it to make it fail
try {
// And we can use ES7 async/await to pull the ISS's position from the open API.
var result = await getJSON(url);
status.end()
showStats(status, 'end()')
} catch (error) {
status.abort()
showStats(status, 'abort()')
}
if (!!result) {
// RunKit will automatically display the last statement and try to find its best representation:
result.iss_position;
}
```
### Example output
```log
Let's see where the ISS is with Node v14.20.1
new AsyncStatus()
- Attempts: 0
- successful: 0
- failed: 0
- State:
- idle: true
- ongoing: false
- Outcome:
- successful: false
- failed: false
- Time elapsed: -1 ms
start()
- Attempts: 1
- successful: 0
- failed: 0
- State:
- idle: false
- ongoing: true
- Outcome:
- successful: false
- failed: false
- Time elapsed: 1 ms
end()
- Attempts: 1
- successful: 1
- failed: 0
- State:
- idle: true
- ongoing: false
- Outcome:
- successful: true
- failed: false
- Time elapsed: 75 ms
```