Paul Underwood
PaulundSoftware Engineer

The tryWhen Function in JavaScript

The tryWhen function is a utility function that allows you to retry a function until a condition is met. It takes four parameters:

  • fn: The function to execute
  • condition: A function that returns a boolean
  • retries: The number of times to retry the function
  • delay: The delay in milliseconds before the next attempt

Here's the implementation of the tryWhen function:

export function tryWhen(fn, condition, retries = 3, delay = 1000) {
    let attempts = 0;

    function attempt() {
        if (!condition() && attempts < retries) {
            attempts++;
            setTimeout(attempt, delay); // Add delay before next attempt
        } else if (attempts < retries) {
            return fn();
        } else {
            throw new Error("Condition not met after " + retries + " attempts");
        }
    }

    attempt();
}

Here's an example of how you can use the tryWhen function to retry a function until a condition is met:

tryWhen(
    () => {
        console.log("Trying...");
        return Math.random();
    },
    () => {
        console.log("Checking...");
        return Math.random() > 0.5;
    }
);

The tryWhen function can be particularly useful in scenarios where you need to execute a function, but the success of that function depends on certain conditions that might not be met immediately.

For example, consider a scenario where you are building a web application that fetches data from an API. Sometimes, due to network issues or server-side processing, the API might not respond immediately or return the expected data. In such cases, you might want to retry the API call after a certain delay, but only if a specific condition is met (like the network is available or server has finished processing).

The tryWhen function can be used to implement this retry logic in a clean and concise manner.

tryWhen(
    () => fetch('https://api.example.com/data'), // Function to execute (API call)
    () => navigator.onLine, // Condition to check (network is available)
    5, // Number of retries
    2000 // Delay in milliseconds
);

In this example, the fetch function will be retried up to 5 times with a delay of 2 seconds between each attempt, but only if the network is available (navigator.onLine returns true). If the network is not available after 5 attempts, an error will be thrown.

Error Handling

The tryWhen function throws an error if the condition is not met after the specified number of retries. You can catch this error and handle it as needed.

try {
    tryWhen(
        () => fetch('https://api.example.com/data'), // Function to execute (API call)
        () => navigator.onLine, // Condition to check (network is available)
        5, // Number of retries
        2000 // Delay in milliseconds
    );
} catch (error) {
    console.error("Failed to fetch data:", error.message);
}

In this example, if the network is not available after 5 attempts, the error message "Failed to fetch data: Condition not met after 5 attempts" will be logged to the console.

Return Value

The tryWhen function returns the result of the function fn if the condition is met within the specified number of retries. If the condition is not met after the retries, an error is thrown.

const data = tryWhen(
    () => fetch('https://api.example.com/data'), // Function to execute (API call)
    () => navigator.onLine, // Condition to check (network is available)
    5, // Number of retries
    2000 // Delay in milliseconds
);

In this example, the data variable will contain the result of the API call if the condition is met within 5 retries. If the condition is not met after 5 retries, an error will be thrown.

Other Approaches

If you need to use this approach for API calls, you might want to consider using a library like Axios, which provides built-in support for retrying requests with configurable options. However, the tryWhen function can be useful in scenarios where you need to retry any function until a condition is met.

There is also a package called retry-axios that provides a similar functionality for Axios requests. retry-axios

There's also async-retry which provides a more comprehensive solution for retrying asynchronous functions with configurable options. async-retry.

There is also Promise.retry which provides a similar functionality for retrying promises. Promise.retry