MODULE 2: ASYNCHRONOUS \& REACTIVE PROGRAMMING Flashcards

(20 cards)

1
Q

What is asynchronous programming, and why has it become central in modern concurrent systems?

A

Asynchronous programming is a style where code can initiate tasks that run independently of the main thread, allowing execution to continue without blocking and wait only for results when needed. It’s crucial because it enables high responsiveness (e.g., serving multiple clients, handling tasks like I/O or network requests) and efficient use of resources without costly thread management.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Describe the event-driven programming model and its typical control flow.

A

In event-driven programming, control flow is dictated by events (user input, messages, etc.). An event loop awaits events and dispatches them to handlers, which process the events. After handler execution, control returns to the event loop, ensuring the program remains responsive. No call stack persists between event handlers—each handler executes atomically.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is the “never-blocking rule” for event-handlers?

A

Event handlers should never block or contain infinite loops. Blocking a handler would block the entire event loop, making the program unresponsive and preventing queued events from processing. Instead, long-running tasks should be offloaded asynchronously, generating new events upon completion.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Explain “callbacks” and “continuation-passing style”.

A

Callbacks are functions provided as arguments, executed when an asynchronous operation completes. In continuation-passing style (CPS), computation is split so every function receives another function (the continuation) to be called with its result. This eliminates reliance on the stack and enables async flows, prominent in evented systems and functional programming.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What are the main challenges and pitfalls of callback-based asynchronous code?

A

Callback hell (deeply nested callbacks, hard to maintain/read), loss of composability, difficulty in error handling, and fragmentation of control flow (“asynchronous spaghetti”). These problems hinder modularity, extensibility, and reasoning.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

How do “promises” improve asynchronous programming over callbacks?

A

A Promise represents an eventual result from an asynchronous operation. It can be resolved or rejected once and provides a clean API to attach completion handlers. Promises allow chaining of async actions (flattening the callback pyramid), centralize error handling, and simplify sequencing or parallelism.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

How is “Promise.all” different from “Promise.race” in JavaScript?

A

Promise.all allows several async actions to run in parallel and resolves when all are complete (or rejects if any fail); Promise.race resolves/rejects as soon as one member of the group does, useful for timeouts or “first response” scenarios.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What problems remain with promises?

A

Promises begin execution immediately (no control over scheduling/cancellation), don’t work naturally with loops, and cannot be cancelled once started, potentially wasting resources. Composition (e.g., parameter passing) can be tricky, and integrating with legacy callback-based code may introduce complexity.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Describe “async/await” and its main benefits.

A

Async/await is a language feature letting developers write asynchronous code in synchronous style. “async” functions always return Promises; “await” can pause (yield) within those functions until a Promise settles. This improves readability, enables error propagation via try/catch, supports loops, and modularizes async code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What are “coroutines”, and how do they relate to asynchronous programming?

A

Coroutines are generalizations of subroutines that can pause (yield) execution and be resumed later. They allow multiple entry points and maintain local state across pauses. Coroutines enable lightweight concurrency, cooperative multitasking, and underpin async programming and event loops in languages like Python, Kotlin, Go.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Explain the “reactor pattern” and its role in high-performance networking.

A

The reactor pattern demultiplexes events from multiple sources (I/O, timers) using a single thread of control (“event loop” or “dispatcher”) and dispatches event handlers based on event type/source readiness. It is widely used in high-concurrency servers, e.g., Node.js, and decouples event sources from processing logic.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How does “reactive programming” differ from classic async/event-driven programming?

A

Reactive programming is oriented around data flows and propagation of change—system components automatically react/update when dependencies change. Unlike classic event-driven async code, which requires manual state propagation between handlers, reactive programming abstracts away explicit control flow and lets the system maintain consistency reactively.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What are the basic abstractions in reactive programming?

A
  • Observable/Event stream: Represents discrete, asynchronous data/events over time.
  • Behaviours/Signals: Represent continuous values over time.
    Both support operators for composition, filtering, transformation, combination, and subscription.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Explain “push” vs. “pull” evaluation models in reactive systems.

A
  • Push: Data producers actively send updates to consumers; propagation occurs as soon as data changes (“eager”).
  • Pull: Consumers request new data when needed (“lazy”); computation happens only if demand exists.
    Hybrid models (push-pull) exist for optimal backpressure and performance.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is “backpressure”, and why is it important in reactive streams?

A

Backpressure is a flow-control mechanism allowing consumers to signal producers about their capacity—preventing memory overload and processing bottlenecks. Producers can buffer, batch, or drop events/data to match consumer speed, critical for scalable async pipeline design.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What’s the difference between “cold” and “hot” observables?

A

Cold observables initiate a new data stream for each subscriber (each gets all events from start); hot observables emit events regardless of subscribers, and late joiners only get data from their subscription point onwards.

17
Q

What is the Observer pattern and how is it used in reactive programming?

A

The Observer pattern lets objects (“observers”) subscribe to another object (“subject”) for notifications of updates or changes. In reactive programming, observables notify subscribers automatically, enabling dataflow dependency propagation and event-driven design.

18
Q

How do reactive libraries (e.g., RxJS, RxJava) support composition and error handling?

A

These libraries provide rich operators for composing streams (map, filter, merge, zip) and centralize error handling—exceptions propagate to subscribers, and operators can define custom recovery strategies (onErrorReturn, etc.). Declarative style enables complex event/data orchestration.

19
Q

What is a “glitch” in reactive systems, and how can it be avoided?

A

A glitch is a momentary inconsistency during dependency graph updates, where computations may be performed before all dependencies are updated, leading to incorrect intermediate states. Avoiding glitches requires topological sorting of update propagation, ensuring all dependencies are recalculated before dependents.

20
Q

What are the main challenges of integrating asynchronous and reactive programming with modularity, testing, and state management?

A

Complex control flow and fragmented error handling complicate modularity and extensibility. Testing is harder due to non-determinism of event arrival and order. Managing shared state or propagating change reliably across hierarchies demands disciplined design and solid abstraction (e.g., observables, state containers).