Javascript uses an event loop model to perform asynchronous operations even though it is single-threaded. Callbacks are used to handle asynchronous operations but can make code complex. Promises were introduced to simplify asynchronous code. A Promise represents the eventual completion (or failure) of an asynchronous operation, and allows consuming code to define callbacks instead of nesting callbacks. Promises are constructed by calling new Promise(), which takes a resolver function with resolve and reject parameters. The state of a Promise can be pending, fulfilled, or rejected.