skip to Main Content

I want to avoid polluting the top-level scope of my file – I am trying to encapsulate the variables into a closure.

Current code:

// global scope - I want to keep track fo these variables between function calls
const timeInMsToReleaseNotification = 1000 * 15; // 15 seconds
let queuedNotifications: Notification[] = [];
let timeoutId: NodeJS.Timeout | null = null;

const trackNotifications = (data: Notification) => {
  if (timeoutId) {
    clearTimeout(timeoutId);
  }

  queuedNotifications.push(data);

  timeoutId = setTimeout(() => {
    const foundData = queuedNotifications[0];

    if (foundData) {
      displayNotification(
        foundData,
        queuedNotifications.length > 1
          ? 'nearbyBatch'
          : 'nearbySingle',
      );
      queuedNotifications = [];
      timeoutId = null;
    }
  }, timeInMsToReleaseNotification);
};

How I would like it to work:

const trackNotifications = (data: Notification) => {
  const timeInMsToReleaseNotification = 1000 * 15; // 15 seconds
  let queuedNotifications: Notification[] = [];
  let timeoutId: NodeJS.Timeout | null = null;
  
  return () => {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }

    queuedNotifications.push(data);

    timeoutId = setTimeout(() => {
      const foundData = queuedNotifications[0];

      if (foundData) {
        displayNotification(
          foundData,
          queuedNotifications.length > 1
            ? 'nearbyBatch'
            : 'nearbySingle',
        );
        queuedNotifications = [];
        timeoutId = null;
      }
    }, timeInMsToReleaseNotification);
  }
};

// calling fn like this
trackNotifications(data)()

This is not working atm.
What am I doing wrong here?

2

Answers


  1. Every time you call trackNotifications() you create a new, empty queuedNotifications array. You need to wrap all the code in an IIFE to create a closure, so the declaration of queuedNotifications is outside the trackNotifications() function.

    ((data) => {
      const timeInMsToReleaseNotification = 1000 * 15; // 15 seconds
      let queuedNotifications: Notification[] = [];
      let timeoutId: NodeJS.Timeout | null = null;
    
      const trackNotifications = (data: Notification) => {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
    
        queuedNotifications.push(data);
    
        timeoutId = setTimeout(() => {
          const foundData = queuedNotifications[0];
    
          if (foundData) {
            displayNotification(
              foundData,
              queuedNotifications.length > 1 ?
              'nearbyBatch' :
              'nearbySingle',
            );
            queuedNotifications = [];
            timeoutId = null;
          }
        }, timeInMsToReleaseNotification);
      };
    
      trackNotifications(data);
    })(data);

    However, in ES6 you don’t need a closure for this. Variables declared with let and const are block-scoped, so you can simply put all the code inside a block.

    {
      const timeInMsToReleaseNotification = 1000 * 15; // 15 seconds
      let queuedNotifications: Notification[] = [];
      let timeoutId: NodeJS.Timeout | null = null;
    
      const trackNotifications = (data: Notification) => {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
    
        queuedNotifications.push(data);
    
        timeoutId = setTimeout(() => {
          const foundData = queuedNotifications[0];
    
          if (foundData) {
            displayNotification(
              foundData,
              queuedNotifications.length > 1 ?
              'nearbyBatch' :
              'nearbySingle',
            );
            queuedNotifications = [];
            timeoutId = null;
          }
        }, timeInMsToReleaseNotification);
      };
    
      trackNotifications(data);
    }
    Login or Signup to reply.
  2. One thing you could do is wrap the whole thing within an IIFE. This limits the scope of the variables so only trackNotifications can access them.

    const trackNotifications = (function () {
      const timeInMsToReleaseNotification = 1000 * 15; // 15 seconds
      let queuedNotifications: Notification[] = [];
      let timeoutId: NodeJS.Timeout | null = null;
    
      // executed when you call `trackNotifications(data)`
      return (data: Notification) => {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
    
        queuedNotifications.push(data);
    
        timeoutId = setTimeout(() => {
          const foundData = queuedNotifications[0];
    
          if (foundData) {
            displayNotification(
              foundData,
              queuedNotifications.length > 1
                ? 'nearbyBatch'
                : 'nearbySingle',
            );
            queuedNotifications = [];
            timeoutId = null;
          }
        }, timeInMsToReleaseNotification);
      };
    })();
    
    // call the function like this
    trackNotifications(data);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search