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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Debouncing collapses a burst of events into a single call after activity settles.
- 2Closures let a factory function keep private per-instance state like timers and pending args.
- 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.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/debouncing-window-resize-in-typescript-explained-typescript-9daa/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.