typescript 34 lines · 6 steps

Debouncing window resize in TypeScript

A self-contained resize observer that debounces rapid events and hands back a cleanup function.

Explained by highlit
1type ResizeCallback = (size: { width: number; height: number }) => void;
2 
3export function observeResize(callback: ResizeCallback, delay = 150) {
4 let timeoutId: ReturnType<typeof setTimeout> | undefined;
5 let lastArgs: { width: number; height: number } | null = null;
6 
7 const flush = () => {
8 timeoutId = undefined;
9 if (lastArgs) {
10 callback(lastArgs);
11 lastArgs = null;
12 }
13 };
14 
15 const handleResize = () => {
16 lastArgs = { width: window.innerWidth, height: window.innerHeight };
17 if (timeoutId !== undefined) {
18 clearTimeout(timeoutId);
19 }
20 timeoutId = setTimeout(flush, delay);
21 };
22 
23 window.addEventListener("resize", handleResize, { passive: true });
24 handleResize();
25 
26 return () => {
27 window.removeEventListener("resize", handleResize);
28 if (timeoutId !== undefined) {
29 clearTimeout(timeoutId);
30 timeoutId = undefined;
31 }
32 lastArgs = null;
33 };
34}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Debouncing collapses a burst of events into a single call after activity settles.
  2. 2Closures let a factory function keep private per-instance state like timers and pending args.
  3. 3Returning a cleanup function pairs setup with teardown so listeners and timers never leak.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
javascript
function evaluate(expression) {
  const tokens = tokenize(expression);
  let pos = 0;
 

Building a recursive descent calculator

parsing recursion operator-precedence
Intermediate 8 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core';
 
interface Preferences {
  theme: 'light' | 'dark';

A signal-based preferences store in Angular

signals state-management persistence
Intermediate 7 steps
go
func (w *Watcher) resetDebounce(d time.Duration) {
	if !w.timer.Stop() {
		select {
		case <-w.timer.C:

Debouncing a stream of events in Go

debounce timers channels
Advanced 7 steps

Share this explainer

Here's the card — post it anywhere.

Debouncing window resize in TypeScript — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code