Frontend Development 11 min read

Implementing createPromise and createRetryPromise Utility Functions in JavaScript

This article explains the design and step‑by‑step implementation of two JavaScript utility functions—createPromise for exposing a Promise’s resolve/reject handlers and createRetryPromise for adding configurable retry logic—complete with TypeScript typings, detailed code walkthroughs, and a practical network‑request example.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing createPromise and createRetryPromise Utility Functions in JavaScript

1. Understanding the createPromise Function

The createPromise function is a custom utility that creates a clean Promise instance and exposes its resolve and reject functions to the outer scope, making it easier to integrate with business logic.

export function createPromise
(): [Promise
, (value: T) => void, (reason?: unknown) => void] {
  let resolve: (value: T) => void = () => {};
  let reject: (reason?: unknown) => void = () => {};
  const promise = new Promise
((res, rej) => {
    resolve = res;
    reject = rej;
  });
  return [promise, resolve, reject];
}

Step‑by‑step analysis

Exported function returns a tuple containing the Promise and its control functions.

Initial placeholders for resolve and reject are defined.

A new Promise is created; its internal res and rej are assigned to the outer variables.

The tuple is returned, allowing callers to resolve or reject the Promise manually.

2. Implementations

2.1 Simple version

The simple version is the code shown above.

2.2 Chromium source‑code inspired version

Based on Chromium’s promise_resolver.ts , a class PromiseResolver encapsulates the same idea.

export class PromiseResolver
{
  private resolve_: (arg: T) => void = () => {};
  private reject_: (arg: any) => void = () => {};
  private isFulfilled_: boolean = false;
  private promise_: Promise
;

  constructor() {
    this.promise_ = new Promise((resolve, reject) => {
      this.resolve_ = (resolution: T) => { resolve(resolution); this.isFulfilled_ = true; };
      this.reject_ = (reason: any) => { reject(reason); this.isFulfilled_ = true; };
    });
  }

  get isFulfilled(): boolean { return this.isFulfilled_; }
  get promise(): Promise
{ return this.promise_; }
  get resolve() { return this.resolve_; }
  get reject() { return this.reject_; }
}

export function createPromise
() { return new PromiseResolver
(); }

2.3 createRetryPromise with task status and retry mechanism

2.3.1 Full implementation

export const createRetryPromise =
(opt: {
  runTask: () => Promise
;
  checkSuccess: (info: T, time: number) => boolean;
  time: number;
  delayTime?: number;
  onTry?: (time: number) => void;
}) => {
  const maxTime = Math.max(1, opt.time);
  const delayTime = Math.max(0, opt.delayTime || 0);
  let time = 0;
  let isCancel = false;
  let reject: (reason?: any) => void = () => {};
  let resolve: (value?: T) => void = () => {};
  let isFinish = false;

  const isNeedRetry = () => time < maxTime && !isCancel && !isFinish;

  const run = () => {
    if (isCancel) return;
    opt.onTry?.(time);
    opt.runTask()
      .then(message => {
        if (isCancel) return;
        if (opt.checkSuccess(message, time)) {
          time = maxTime;
          resolve(message);
        } else {
          time++;
        }
      })
      .catch(() => { time++; })
      .finally(() => {
        if (isNeedRetry()) {
          setTimeout(run, delayTime);
        } else {
          reject('timeout');
        }
      });
  };

  const cancel = () => {
    isCancel = true;
    reject('cancel');
  };

  return {
    cancel,
    getResult: () => new Promise
((res, rej) => {
      reject = rej;
      resolve = res;
      run();
    }).finally(() => { isFinish = true; })
  };
};

2.3.2 Step‑by‑step analysis

Define function signature and options (task, success check, retry count, delay, optional hook).

Initialize control variables: max attempts, delay, counters, cancellation flag, and placeholders for resolve / reject .

Implement run which executes the task, checks success, increments counters, and schedules retries with setTimeout if needed.

Provide cancel to abort retries and reject the Promise.

Return an object exposing cancel and getResult , the latter yielding a Promise that resolves when the task succeeds or rejects on timeout/cancel.

3. Practical Use Case

Using createRetryPromise to implement a resilient network request with automatic retries:

const fetchWithRetry = createRetryPromise({
  runTask: () => fetch('https://api.example.com/data'),
  checkSuccess: (response, time) => response.ok || time >= 3,
  time: 5,
  delayTime: 1000,
  onTry: (time) => console.log(`Retrying... (attempt ${time})`)
});

fetchWithRetry.getResult()
  .then(response => response.json())
  .then(data => console.log('Data:', data))
  .catch(error => console.error('Error:', error));

This example demonstrates how the utilities simplify handling flaky network calls by abstracting retry logic and exposing control over resolution.

TypeScriptJavaScriptretryUtilityasyncPromise
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.