Before fetch, XMLHttpRequest (XHR) made requests via an event-based API: open, set onload/onerror, then send. It's verbose and callback-driven. You rarely write new XHR, but you'll read it in legacy code, and it still has one edge: native upload progress events, which fetch lacked for a long time.