Creating APIs with $

A powerful feature of the Optimizer is that you can create your own APIs with a $ suffix.

Imagine that we would like to have a delay method that lazy loads its callback. Normally we would have to write something like this:

setTimeout(() => {
  // I am eagerly loaded, but it would be better if I was lazy-loaded.
  ...
}, timeout);

The issue with the example above is that the callback has to be downloaded and created eagerly. This may be an issue if the closure is large or if the callback is never executed (or only executed later.)

A better solution would be to have delay$ method that can lazy-load the closure associated with the callback. Something like this.

delay$(() => {
  // I am lazy-loaded only when I need to be executed.
  ...
}, 1000)

In the above solution, the callback is only downloaded when delay$ is ready to execute it.

Creating your APIs with $ suffix

Qwik runtime works with QRLs. For this reason we define a method like so:

export function delayQrl<T>(fn: QRL<() => T>, delayInMs: number): Promise<T> {
  return new Promise((res) => {
    setTimeout(() => {
      res(fn.invoke());
    }, delayInMs);
  });
}

This method knows how to take a QRL and execute it after a certain delay. The key part here is that the QRL.invoke() method is called when the delay is ready and is therefore lazy.

The next step is to convert the delayQrl method to a delay$ alias. This is done with implicit$FirstArg like so:

export const delay$ = implicit$FirstArg(delayQrl);

Here are the types to make it clearer as to what is going on.

declare function delayQrl<T>(fn: QRL<() => T>, delayInMs: number): Promise<T>;
declare function delay$<T>(fn: () => T, delayInMs: number): Promise<T>;

The above allows us to use delay$ in an inlined fashion, but the Optimizer converts the delay$ to delayQrl form.

NOTE the two methods must have the same prefix. So a general form is:

export const SOME_NAME_Qrl = ...;
export const SOME_NAME_$ = implicit$FirstArg(SOME_NAME_Qrl);

Example

In our example we are executing store.count++ and store.delay++ together. Wrap the store.delay in delay$() call so that it updates with a one second delay.

Edit Tutorial