Abstract Executor class
Executor
is a class derived from Promise
and it has similar behavior but with one major difference: asynchronous operation that ties an outcome to a promise is decoupled from the constructor.
Executor
also has two useful features:
- Built-in monitoring of execution time
- Optional rejection by a specified timeout
The package additionally includes a simple executor implementation called Receiver
.
Installation
Install with npm:
npm install @js-bits/executor
Install with yarn:
yarn add @js-bits/executor
Import where you need it:
import { Executor, Receiver } from '@js-bits/executor';
or require for CommonJS:
const { Executor, Receiver } = require('@js-bits/executor');
How to use
Since asynchronous operation is decoupled it won't be executed automatically when a new Executor
gets created. Instead you have to call .execute()
method explicitly.
const asyncOperation = new Executor((resolve, reject) => {
resolve(123);
});
asyncOperation.execute();
asyncOperation.then(result => {
console.log('result', result);
});
Execution timings
There are five metrics available any time through timings
property:
CREATED
EXECUTED
RESOLVED
REJECTED
SETTLED
(equals to either RESOLVED
or REJECTED
)
Use Executor.STATES
static enum property in order to access them.
class DOMReadyReceiver extends Executor {
constructor(...args) {
super((resolve, reject) => {
if (document.readyState === 'complete' || document.readyState === 'interactive') {
resolve(true);
} else {
window.addEventListener('DOMContentLoaded', () => {
resolve(false);
});
}
}, ...args);
this.execute();
}
}
const { CREATED, EXECUTED, RESOLVED } = DOMReadyReceiver.STATES;
(async () => {
const domReady = new DOMReadyReceiver();
const isDomReady = await domReady;
console.log(`DOMReadyReceiver created in ${domReady.timings[CREATED] / 1000} s`);
console.log(`${isDomReady ? 'DOM ready' : 'DOMContentLoaded'} in ${domReady.timings[RESOLVED] / 1000} s`);
console.log(`Delay: ${domReady.timings[RESOLVED] - domReady.timings[EXECUTED]} ms`);
})();
Timeout
You can use optional timeout
parameter to set maximum allowable execution time for the asynchronous operation. There are 2 types of timeout supported:
Hard timeout. The executor will be automatically rejected when specified timeout is exceeded. It can be set by an integer number passed as a value of timeout
parameter.
import Timeout from '@js-bits/timeout';
const asyncOperation = new Executor(
(resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
},
{
timeout: 100,
}
);
(async () => {
const { EXECUTED, RESOLVED, SETTLED } = Executor.STATES;
asyncOperation.execute();
try {
await asyncOperation;
console.log(`Resolved in ${(asyncOperation.timings[RESOLVED] - asyncOperation.timings[EXECUTED]) / 1000} s`);
} catch (reason) {
if (reason.name === Timeout.TimeoutExceededError) {
console.log(`Timed out in ${asyncOperation.timings[SETTLED] - asyncOperation.timings[EXECUTED]} ms`);
}
}
})();
Soft timeout. Can be set by a Timeout instance passed as a value of timeout
parameter. The executor won't be rejected automatically. The timeout must be handled externally.
import Timeout from '@js-bits/timeout';
const asyncOperation = new Executor(
(resolve, reject) => {
setTimeout(() => {
resolve('Success!!!');
}, 1000);
},
{
timeout: new Timeout(100),
}
);
(async () => {
asyncOperation.execute();
asyncOperation.timeout.catch(reason => {
if (reason.name === Timeout.TimeoutExceededError) {
console.log('Operation has exceeded specified timeout.');
}
});
console.log(await asyncOperation);
})();
Receiver
Receiver
does not accept any executor function which basically means that it doesn't perform any actions by itself. Receiver
can be used to asynchronously assign a value to some variable or indicate some event.
const someAsyncValue = new Receiver();
const { EXECUTED, RESOLVED } = Receiver.STATES;
(async () => {
setTimeout(() => {
someAsyncValue.resolve(123);
}, 1000);
console.log(`Received value: ${await someAsyncValue}`);
console.log(`It took ${someAsyncValue.timings[RESOLVED] - someAsyncValue.timings[EXECUTED]} ms to receive the value`);
})();
Notes
- Loader - an implementation of
Executor
for HTTP requests.