@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
176 lines • 6.18 kB
JavaScript
/**
* @module Async
*/
import { AsyncHooks, callInvokable, resolveAsyncLazyable, } from "../../../utilities/_module-exports.js";
import { abortAndFail } from "../../../async/utilities/abort-and-fail/_module.js";
/**
* The `LazyPromise` class is used for creating lazy {@link PromiseLike | `PromiseLike`} object that will only execute when awaited or when `then` method is called.
* Note the class is immutable.
*
* IMPORT_PATH: `"@daiso-tech/core/async"`
* @group Utilities
*/
export class LazyPromise {
/**
* The `wrapFn` is convience method used for wrapping async {@link Invokable | `Invokable`} with a `LazyPromise`.
* @example
* ```ts
* import { LazyPromise, retry } from "@daiso-tech/core/async";
* import { TimeSpan } from "@daiso-tech/core/utilities";
* import { readFile as readFileNodeJs } from "node:fs/promises";
*
* const readFile = LazyPromise.wrapFn(readFileNodeJs);
*
* const file = await readFile("none_existing_file.txt");
* ```
*/
static wrapFn(fn) {
return (...parameters) => new LazyPromise(() => callInvokable(fn, ...parameters));
}
/**
* The `delay` method creates a {@link LazyPromise | `LazyPromise`} that will be fulfilled after given `time`.
*
* @example
* ```ts
* import { LazyPromise } from "@daiso-tech/core/async";
* import { TimeSpan } from "@daiso-tech/core/utilities";
*
* console.log("a");
* await LazyPromise.delay(TimeSpan.fromSeconds(2));
* console.log("b");
* ```
*/
static delay(time, abortSignal = new AbortController().signal) {
return new LazyPromise(async () => {
let timeoutId = null;
try {
await abortAndFail(new Promise((resolve) => {
timeoutId = setTimeout(() => {
resolve();
}, time.toMilliseconds());
}), abortSignal);
}
finally {
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
}
});
}
/**
* The `all` method works similarly to {@link Promise.all | `Promise.all`} with the key distinction that it operates lazily.
*/
static all(promises) {
return new LazyPromise(async () => Promise.all(promises));
}
/**
* The `allSettled` method works similarly to {@link Promise.allSettled | `Promise.allSettled`} with the key distinction that it operates lazily.
*/
static allSettled(promises) {
return new LazyPromise(async () => Promise.allSettled(promises));
}
/**
* The `race` method works similarly to {@link Promise.race | `Promise.race`} with the key distinction that it operates lazily.
*/
static race(promises) {
return new LazyPromise(async () => Promise.race(promises));
}
/**
* The `any` method works similarly to {@link Promise.any | `Promise.any`} with the key distinction that it operates lazily.
*/
static any(promises) {
return new LazyPromise(async () => Promise.any(promises));
}
/**
* The `fromCallback` is convience method used for wrapping Node js callback functions with a `LazyPromise`.
* @example
* ```ts
* import { LazyPromise } from "@daiso-tech/core/async";
* import { readFile } from "node:fs";
*
* const lazyPromise = LazyPromise.fromCallback<Buffer | string>((resolve, reject) => {
* readFile("FILE_PATH", (err, data) => {
* if (err !== null) {
* reject(err);
* return;
* }
* resolve(data);
* });
* });
* const file = await lazyPromise;
* console.log(file);
* ```
*/
static fromCallback(callback) {
return new LazyPromise(() => new Promise((resolve, reject) => {
callback(resolve, reject);
}));
}
promise = null;
invokable;
/**
* @example
* ```ts
* import { LazyPromise, retryMiddleware } from "@daiso-tech/core/async";
*
* const promise = new LazyPromise(async () => {
* console.log("I am lazy");
* },
* // You can also pass in one AsyncMiddleware or multiple (as an Array).
* retry()
* );
*
* // "I am lazy" will only logged when awaited or then method i called.
* await promise;
* ```
*
* You can pass sync or async {@link Invokable | `Invokable`}.
*/
constructor(invokable, middlewares = []) {
this.invokable = new AsyncHooks(() => resolveAsyncLazyable(invokable), middlewares);
}
/**
* The `pipe` method returns a new `LazyPromise` instance with the additional `middlewares` applied.
*/
pipe(middlewares) {
return new LazyPromise(this.invokable.pipe(middlewares));
}
/**
* The `pipeWhen` method conditionally applies additional `middlewares`, returning a new `LazyPromise` instance only if the specified condition is met.
*/
pipeWhen(condition, middlewares) {
return new LazyPromise(this.invokable.pipeWhen(condition, middlewares));
}
then(onfulfilled, onrejected) {
if (this.promise === null) {
this.promise = this.invokable.invoke();
}
// eslint-disable-next-line @typescript-eslint/use-unknown-in-catch-callback-variable
return this.promise.then(onfulfilled, onrejected);
}
/**
* The `defer` method executes the `LazyPromise` without awaiting it.
* @example
* ```ts
* import { LazyPromise } from "@daiso-tech/core/async";
* import { TimeSpan } from "@daiso-tech/core/utilities";
*
* const promise =
* new LazyPromise(async () => {
* await LazyPromise.delay(TimeSpan.fromSeconds(1));
* // Will be loged after one second
* console.log("Done !");
* });
*
* promise.defer();
*
* // Will be logged immediately
* console.log("Hello");
* await LazyPromise.delay(TimeSpan.fromSeconds(2));
* ```
*/
defer() {
this.then(() => { });
}
}
//# sourceMappingURL=lazy-promise.js.map