You are viewing the preview version of this book
Click here for the full version.

The async serializer pattern

Let's say you have a function that does some calculation but only if it hasn't been done recently, effectively caching the result for a short amount of time. In this case, subsequent calls to the function affect each other, as when there is a refresh all of them need to wait for it. An implementation that does not take concurrency into account can potentially run the refresh several times in parallel when the cache expires.

This implementation is broken:

// returns a function that caches its result for 2 seconds
// broken, don't use it
const badCachingFunction = (() => {
  const cacheTime = 2000;
  let lastRefreshed = undefined;
  let lastResult = undefined;
  return async () => {
    const currentTime = new Date().getTime();
    // check if cache is fresh enough
    if (lastResult === undefined ||
      lastRefreshed + cacheTime < currentTime) {
      // refresh the value
      lastResult = await refresh();
      lastRefreshed = currentTime;
    }
    return lastResult;
  }
})();

When two concurrent calls come when the function needs to refresh the value, the refresh function is called twice:

const wait = (ms) => new Promise((res) => setTimeout(res, ms));

const refresh = async () => {
  console.log("refreshing")
  await wait(1000);
};

const badCachingFunction = ...;

badCachingFunction();
badCachingFunction();
// refreshing
// refreshing

The correct way to handle this is to make the second function wait for the refresh process without starting a separate one.

One way to do this is to serialize the calls to the caching function. This makes every function to wait for all the previous ones to finish, so multiple calls only trigger a single refresh process.

This can be done in a variety of ways, but the easiest one is to make the functions run one after the other. In this case, when one needs to refresh the value, the other ones will wait for it to finish and won't start their own jobs.

There is more, but you've reached the end of this preview
Read this and all other chapters in full and get lifetime access to:
  • all future updates
  • full web-based access
  • PDF and Epub versions