4Developers Łódź 2024: Szymon Chmal - Praktyczny przewodnik po zadaniach, obietnicach i planowaniu
Engineers explore architecture and security mechanisms for 4Developers Łódź 2024: Szymon Chmal - Praktyczny przewodnik po zadaniach, obietnicach i planowaniu.
Summary
## Overview
Szymon Chmal presents a comprehensive guide to understanding JavaScript's task execution model, asynchronous programming, and practical strategies for optimizing long-running operations. The talk addresses common misconceptions about how JavaScript handles asynchronous work and provides real-world solutions for keeping web applications responsive.
## Key Topics
**Event Loop and Tasks** All code execution in JavaScript—including event handlers, setTimeout callbacks, and synchronous code—is organized as tasks. The event loop manages a queue of these tasks, executing one at a time. Critically, tasks cannot be interrupted; once started, a task must complete before the next task can begin. This single-threaded model means that long-running synchronous tasks can block user interactions.
**Microtasks vs. Macrotasks** JavaScript distinguishes between macrotasks (regular tasks) and microtasks (created by Promises and MutationObserver). Microtasks use a separate queue that must be completely emptied before the next macrotask begins. This detail matters: wrapping work in a Promise does not run it "in the background" but instead schedules a microtask that still executes on the main thread, blocking interactions during execution.
**Task Splitting and "Yield to Main"** The speaker demonstrates a practical pattern for breaking long-running work into smaller chunks: the "yield to main" function. This function returns a Promise that resolves after a setTimeout(0), creating a new task. By inserting yields between work chunks, the browser can execute higher-priority tasks (like button clicks or text input) between chunks, maintaining responsiveness. A real-world example: validating a form with 60 nodes and 14 properties per node, originally taking 6 seconds, became responsive by splitting validation into smaller subtasks with yield points.
**Scheduling Constraints and Workarounds** setTimeout enforces a 4-millisecond minimum delay when nested more than 4 levels deep, limiting control. To bypass this, some libraries (including React 16+) use the Message Channel API, which allows scheduling without the 4ms throttle—though this is an undocumented workaround.
**Modern Scheduler API** A new Scheduler API (currently supported in Edge and Chrome, behind a flag in Firefox) provides explicit task prioritization: user-blocking (highest), user-visible (default), and background. Tasks include a controller for changing priorities or cancellation mid-execution, and a special yield() method that ensures the current high-priority task completes before lower-priority work resumes.
## Technical Details
**Asynchronous vs. Concurrent** The speaker clarifies that JavaScript is asynchronous but not concurrent. Without WebWorkers, JavaScript has one thread; asynchronicity refers to the ability to schedule work for later (via the event loop), not to parallel execution.
**Microtask Optimization** Promise resolution should be used carefully. Receiving 100 API responses that each trigger a microtask can create 100 microtasks in a single event loop cycle, blocking the browser while all are processed. Batching (e.g., 16 microtasks per batch with macrotasks between) reduces perceived jank.
**Frame-Aware Scheduling** requestAnimationFrame is guaranteed to fire before the browser renders a frame. Wrapping a setTimeout inside a requestAnimationFrame ensures visual updates occur before rendering. requestIdleCallback schedules work during browser idle time, utilizing gaps between frames, but it is not guaranteed to execute if the browser is busy. It accepts an optional timeout to force execution regardless.
## Takeaways
1. **Understand the event loop**: All JavaScript execution revolves around tasks and the event loop; this knowledge is foundational for performance work. 2. **Promises don't run in the background**: Wrapping work in a Promise schedules a microtask on the main thread, not background execution. 3. **Break up long tasks**: Use yield-to-main patterns to insert gaps where the browser can handle user input, keeping applications responsive. 4. **Set deadlines when splitting tasks**: Yield too frequently and context-switching overhead exceeds gains; a 10–50ms deadline per chunk is often reasonable. 5. **Use the right API for the job**: setTimeout for basic scheduling, requestAnimationFrame for visual updates, requestIdleCallback for non-urgent background work, and the Scheduler API for explicit priority control. 6. **Framework behavior**: Frameworks like React use similar task-splitting techniques internally to render large component trees without blocking. 7. **Monitor real-world impact**: Metryki, especially Interaction to Paint, reveal whether optimizations actually help users.
Related talks
PROIDEA Events·34 min
Analysts investigate attack surfaces and defenses concerning 4Developers 2024: Szymon Chmal - Astro - wyspiarska technologia w imię optymalizacji.
PROIDEA Events·38 min
Nowe oblicze hydracji investigates Szymon Chmal.
PROIDEA Events·53 min
Presenters detail vulnerability discovery and exploitation in 4Developers 2016: Graph databases - why and how (Szymon Warda).


