Home > Net >  Typescript: How to use an async IIFE as an addEventListener callback while adhering to the no-misuse
Typescript: How to use an async IIFE as an addEventListener callback while adhering to the no-misuse

Time:11-17

The following code works as expected; it processes a click event and only allows a subsequent click event to occur once the current one is finished processing.

However, since the IIEF closure is async, the return value is Promise<void>, which means that it breaks the no-misused-promises rule with an error of Promise returned in function argument where a void return was expected. Taking away the async is not an option because it would result in having to remove the await on handleClick(), which has resulted in improper throttling of the click events when tested.

let processingClick = false;
  document.getElementById(wikiPageElementId)?.addEventListener('click', async (event) => {
    event.preventDefault();
    if (!processingClick) {
      processingClick = true;
      // `await` needed here so that each event is processed synchronously.
      // Without `await`, any subsequent click could be processed asynchronously
      // while `handleClick()` is running.
      await handleClick(event.target);
      processingClick = false;
    }
  });

CodePudding user response:

There's no need for an IIFE (or an async IIFE) here - using .then or .finally will work just as well. (Consider .finally, because it'll handle both successes and failures)

let processingClick = false;
document.getElementById(wikiPageElementId)?.addEventListener('click', (event) => {
    event.preventDefault();
    if (processingClick) {
        return;
    }
    processingClick = true;
    handleClick(event.target)
        .finally(() => {
            processingClick = false;
        });
});

If you had to use an IIFE, you could declare it inside the click listener.

let processingClick = false;
document.getElementById(wikiPageElementId)?.addEventListener('click', (event) => {
    event.preventDefault();
    void (async () => {
        if (!processingClick) {
            processingClick = true;
            await handleClick(event.target);
            processingClick = false;
        }
    })();
});

(though that may run afoul of other linting rules you may have - the void is needed for no-floating-promises, but you also might have no-void - which is why a better approach would be to avoid async IIFEs entirely)

  • Related