Definition
Event-driven programming is a model in which the flow of a program is determined by events — user actions, sensor outputs, network messages, timer expirations, completion of asynchronous I/O — rather than by a top-down sequence of statements executed in fixed order. The program registers handlers (callbacks, listeners, observers, coroutines) for the events it cares about, then yields control to an event loop that waits for the next event and dispatches it to the appropriate handler.
The model is the dominant idiom for any system that must remain responsive while waiting on the outside world: GUI applications, browser JavaScript, network servers, embedded firmware, game engines, and trading systems. Sequential programming asks "what do I do next?"; event-driven programming asks "what happened, and how should I react?" The inversion of control — the framework calls the application's code, not the other way around — is the defining feature.
Why it matters
How it works
At the center is an event loop — a single piece of code that, in a tight cycle, checks for new events and dispatches each to its registered handler. Events arrive from many sources: the OS notifies the loop when a socket becomes readable, when a timer expires, when a file operation completes, or when the user clicks. The loop pulls the next event from its queue, runs the matching handler to completion, and returns to the loop to pick up the next event. As long as every handler is fast, the loop drains the queue and the program appears responsive. If a handler blocks — a long synchronous calculation, a network call without async wrappers — the whole loop stalls and every other event waits.
Three patterns dominate real-world event-driven code. Callbacks register a function to run when the event fires; they are simple but lead to nested chains ("callback hell") when one event triggers another. Promises and futures wrap the eventual result of an async operation in an object that other code can chain off, flattening the nesting. Async/await syntactically restores the sequential look — await fetch(url) reads like a blocking call but compiles into an event-loop suspension and resumption. Underneath, the event loop is doing the same scheduling in all three styles; what changes is how the application code expresses the dependency between one event and the next.