UNPKG

@ugo-code/streamline.js

Version:

A utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript

80 lines (79 loc) 3.61 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.retry = retry; // --- Default Configuration Constants --- const DEFAULT_LIMIT = 2; const DEFAULT_INITIAL_DELAY = 0; const DEFAULT_MAX_DELAY = Infinity; /** * Executes an asynchronous task and automatically retries it if it fails. * By default, retries happen immediately without any delay. An exponential * backoff delay can be enabled by setting the `initialDelay` option. * * This function is useful for handling transient errors in network requests or * other operations that might succeed on a subsequent attempt. * * @template TResult The expected result type of the asynchronous task. * @param {() => Promise<TResult>} taskFn The asynchronous function to execute. * This function should not take any arguments and must return a Promise. * @param {RetryOptions<TResult>} [options={}] Optional configuration to control * the retry behavior, such as the number of retries and delay timings. * @returns {Promise<TResult>} A promise that either resolves with the task's * successful result or rejects with the last error encountered after all * attempts have been exhausted. * @example * ```ts * // Example 1: Basic usage with default settings (2 retries, no delay) * const data = await retryTask(fetchData); * * // Example 2: Customizing retry behavior to include a delay * const user = await retryTask(fetchUser, { * limit: 3, * initialDelay: 100, // Enable a 100ms initial delay with backoff * onRetry: (error, attempt) => { * console.log(`Attempt ${attempt} failed. Retrying in a moment...`, error); * } * }); * ``` */ function retry(taskFn_1) { return __awaiter(this, arguments, void 0, function* (taskFn, options = {}) { const { limit = DEFAULT_LIMIT, initialDelay = DEFAULT_INITIAL_DELAY, maxDelay = DEFAULT_MAX_DELAY, onRetry, } = options; let lastError; for (let attempt = 0; attempt <= limit; attempt++) { try { return yield taskFn(); } catch (error) { lastError = error; if (attempt === limit) { break; } const exponentialDelay = initialDelay * Math.pow(2, attempt); const delay = Math.min(exponentialDelay, maxDelay); if (typeof onRetry === "function") { try { onRetry(error, attempt + 1, delay); } catch (onRetryError) { console.error("Error within onRetry callback:", onRetryError); } } // Only introduce a delay if it's greater than 0. if (delay > 0) { yield new Promise((resolve) => setTimeout(resolve, delay)); } } } throw lastError; }); }