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 { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';

How a JWT strategy authenticates in NestJS

authentication jwt passport
Intermediate 7 steps
typescript
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { catchError, filter, take, switchMap } from 'rxjs/operators';

Refreshing auth tokens in an Angular interceptor

http-interceptor token-refresh rxjs
Advanced 8 steps
typescript
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';

How a GraphQL auth guard works in NestJS

authentication authorization jwt
Intermediate 7 steps
javascript
const MAX_BATCH_SIZE = 20;
const FLUSH_INTERVAL = 5000;
const ENDPOINT = '/api/analytics';
 

Batching analytics events in the browser

batching buffering sendbeacon
Intermediate 10 steps
rust
use axum::{
    extract::State,
    routing::{get, post, MethodRouter},
    Json, Router,

Self-documenting routes in Axum

builder-pattern closures shared-state
Intermediate 8 steps
typescript
import { Injectable, Logger, OnApplicationShutdown } from '@nestjs/common';
import { InjectRedis } from '@nestjs-modules/ioredis';
import Redis from 'ioredis';
import { DataSource } from 'typeorm';

Graceful shutdown hooks in NestJS

graceful-shutdown lifecycle-hooks dependency-injection
Intermediate 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