4Developers 2017: 5 architectures of asynchronous JavaScript (Tomasz Ducin)
Security researchers examine technical aspects of 4Developers 2017: 5 architectures of asynchronous JavaScript (Tomasz Ducin).
Summary
### Overview In this presentation at 4Developers 2017, Tomasz Ducin addresses a widespread issue among JavaScript developers: a lack of understanding regarding asynchronous execution order and mechanics, which frequently leads to brute-force workarounds and overcomplicated code. Ducin clarifies JavaScript's core concurrency model—a single-threaded, cooperative concurrency system governed by an event loop, message queues, and run-to-completion semantics. The talk walks through five major architectures for managing asynchronous operations: Callbacks, Event-Driven Architecture, Promises, Coroutines/Communicating Sequential Processes (CSP) / Async-Await, and Reactive Streams (RxJS).
### Key Topics - **Concurrency Models and JavaScript Mechanics**: Comparing single-threaded synchronous (blocking, linear), multi-threaded (parallel execution with shared memory requiring semaphores/deadlock handling), and event-driven asynchronous execution. Ducin explains cooperative concurrency versus pre-emptive concurrency, highlighting that JavaScript tasks run to completion and cannot be interrupted by the scheduler. - **Event Loop and Message Queues**: How asynchronous actions (timers, HTTP requests, UI events) push messages and callbacks onto a first-in, first-out queue, which the event loop processes sequentially. Ducin notes that `setTimeout` and `setInterval` guarantee only a minimum delay, not an exact execution time. - **Callbacks and the Event-Driven Approach**: Inspecting synchronous callbacks (`map`, `filter`, IIFEs) versus asynchronous callbacks (`setTimeout`), as well as browser and custom DOM/framework events. The discussion touches on the callback hell / pyramid of doom issue and architectural challenges with multi-directional event flows. - **Promises and Combinators**: Using ES6 Promise objects to handle single deferred computations cleanly in chains. The speaker contrasts sequential versus parallel flows and details combinators including `Promise.all`, `Promise.race`, and Bluebird additions like `Promise.any` and `Promise.some`. - **Generators, Coroutines, and Async/Await**: Combining ES6 generators (`function*`, `yield`, `next()`) with promises to build coroutines, paving the way for the native ES8 `async`/`await` syntax. Ducin also demonstrates Communicating Sequential Processes (CSP) via libraries like `js-csp`. - **Reactive Streams (RxJS)**: Explaining observables and reactive streams as a combination of the Observer pattern, the Iterator protocol, and functional programming, contrasting their multi-value, lazy, and cancellable nature with promises.
### Technical Details - **Run-to-Completion**: If a computationally heavy task processes thousands of DOM nodes or heavy data in a single turn, the browser UI freezes because tasks cannot be pre-empted; resolving this requires slicing work into chunks using `setTimeout` or `setInterval`. - **Promise Mechanics and Aggregates**: - A promise can only transition from `pending` to `fulfilled` or `rejected` once; subsequent attempts to settle are ignored. - `Promise.all` fails immediately if any single promise rejects. - `Promise.race` settles as soon as the first promise settles (resolve or reject). - `Promise.any` requires at least one promise to resolve, rejecting only if all fail; `Promise.some(n)` generalizes this to $n$ resolutions. - **Coroutines & CSP (`js-csp`)**: Coroutines run within a single thread. In CSP, processes communicate via channels using `yield put` (which blocks the process if no receiver is listening) and `yield take` (which blocks until a value is placed in the channel), passing execution back and forth. - **Observables vs. Promises**: Citing André Staltz (author of Cycle.js), Ducin notes that promises are single-value, always asynchronous, eager, and uncancellable, whereas observables handle multiple values, can be synchronous or asynchronous, are lazy (execution starts only upon subscription), and can be cancelled or completed.
### Takeaways A deep grasp of JavaScript fundamentals—specifically function scope, context, closures, and the single-threaded event loop—is required before architecting complex applications. Developers should avoid assumptions about external network request timing to prevent race conditions. While callbacks and events suit simple interactions, modern patterns like `async`/`await` offer synchronous readability for single-value operations, CSP enables coordinated sequential tasks, and reactive streams (RxJS) provide powerful control over multi-event asynchronous pipelines across time.
Related talks
PROIDEA Events·50 min
Tomek Ducin
Industry experts analyze emerging threats surrounding 4Developers 2025: Tomek Ducin - "The many meanings of share and reuse in software architecture.".
PROIDEA Events·37 min
Engineers explore architecture and security mechanisms for 4Developers Łódź 2024: Łukasz Pięta - Embracing Clean Architecture in Spring Boot and Kotlin.
PROIDEA Events·41 min
Analysts investigate attack surfaces and defenses concerning 4Developers Katowice 2024: Tomasz Jakóbiec - In the best teams, all engineers are architects!.


