- Spec files
npm-axios
Describes: pkg:npm/axios@1.6.x
- Description
- Promise based HTTP client for the browser and node.js
- Author
- tessl
- Last updated
request-cancellation.md docs/
1# Request Cancellation23Request cancellation support using modern AbortController and legacy CancelToken for aborting in-flight requests. This allows you to cancel requests that are no longer needed, helping to reduce unnecessary network traffic and improve performance.45## Capabilities67### Modern Cancellation with AbortController89The recommended approach using the standard AbortController API.1011```typescript { .api }12interface GenericAbortSignal {13readonly aborted: boolean;14onabort?: ((...args: any) => any) | null;15addEventListener?: (...args: any) => any;16removeEventListener?: (...args: any) => any;17}18```1920**Usage Examples:**2122```typescript23import axios from "axios";2425// Basic cancellation26const controller = new AbortController();2728const request = axios.get("https://api.example.com/data", {29signal: controller.signal30});3132// Cancel the request33controller.abort();3435try {36const response = await request;37console.log(response.data);38} catch (error) {39if (axios.isCancel(error)) {40console.log("Request was cancelled");41} else {42console.error("Request failed:", error);43}44}4546// Timeout with AbortController47function requestWithTimeout<T>(url: string, timeout: number) {48const controller = new AbortController();4950// Auto-cancel after timeout51const timeoutId = setTimeout(() => {52controller.abort();53}, timeout);5455return axios.get<T>(url, { signal: controller.signal })56.finally(() => {57clearTimeout(timeoutId);58});59}6061// Usage62try {63const response = await requestWithTimeout("https://api.example.com/slow-endpoint", 5000);64console.log(response.data);65} catch (error) {66if (axios.isCancel(error)) {67console.log("Request timed out");68}69}7071// Multiple requests with shared cancellation72const controller = new AbortController();7374const requests = [75"https://api.example.com/users",76"https://api.example.com/posts",77"https://api.example.com/comments"78].map(url => axios.get(url, { signal: controller.signal }));7980// Cancel all requests81setTimeout(() => {82controller.abort();83}, 2000);8485try {86const responses = await Promise.all(requests);87console.log("All requests completed:", responses);88} catch (error) {89if (axios.isCancel(error)) {90console.log("Requests were cancelled");91}92}93```9495### Legacy Cancellation with CancelToken9697Legacy cancellation mechanism maintained for backward compatibility.9899```typescript { .api }100class CancelToken {101/**102* Creates new CancelToken103* @param executor - Function that receives cancel function104*/105constructor(executor: (cancel: Canceler) => void);106107/** Promise that resolves when cancelled */108promise: Promise<Cancel>;109110/** Cancellation reason if cancelled */111reason?: Cancel;112113/** Throw error if already cancelled */114throwIfRequested(): void;115116/**117* Create cancellation source118* @returns Object with token and cancel function119*/120static source(): CancelTokenSource;121}122123interface CancelTokenSource {124token: CancelToken;125cancel: Canceler;126}127128interface Canceler {129(message?: string, config?: AxiosRequestConfig, request?: any): void;130}131132interface Cancel {133message: string | undefined;134}135```136137**Usage Examples:**138139```typescript140import axios, { CancelToken } from "axios";141142// Using CancelToken.source()143const source = CancelToken.source();144145const request = axios.get("https://api.example.com/data", {146cancelToken: source.token147});148149// Cancel the request150source.cancel("Request cancelled by user");151152try {153const response = await request;154console.log(response.data);155} catch (error) {156if (axios.isCancel(error)) {157console.log("Cancelled:", error.message);158}159}160161// Using CancelToken constructor162let cancel: Canceler;163164const request = axios.get("https://api.example.com/data", {165cancelToken: new CancelToken((c) => {166cancel = c;167})168});169170// Cancel later171setTimeout(() => {172cancel("Timeout");173}, 5000);174175// Check if token is already cancelled176const token = source.token;177try {178token.throwIfRequested();179// Token is not cancelled, proceed with request180} catch (error) {181console.log("Token was already cancelled");182}183```184185### CanceledError Class186187Specific error type for cancelled requests.188189```typescript { .api }190class CanceledError<T> extends AxiosError<T> {191// Inherits all properties and methods from AxiosError192}193```194195**Usage Examples:**196197```typescript198import axios, { CanceledError, isCancel } from "axios";199200const controller = new AbortController();201202try {203const response = axios.get("https://api.example.com/data", {204signal: controller.signal205});206207// Cancel the request208controller.abort();209210await response;211} catch (error) {212if (error instanceof CanceledError) {213console.log("Request was cancelled specifically");214} else if (isCancel(error)) {215console.log("Request cancellation detected");216} else {217console.log("Other error occurred");218}219}220```221222### Cancellation Detection223224Utility functions to detect if an error is due to cancellation.225226```typescript { .api }227/**228* Check if error is a cancellation229* @param value - Value to check230* @returns Type predicate indicating if value is Cancel231*/232function isCancel(value: any): value is Cancel;233```234235**Usage Examples:**236237```typescript238import axios, { isCancel } from "axios";239240async function fetchData(signal?: AbortSignal) {241try {242const response = await axios.get("https://api.example.com/data", { signal });243return response.data;244} catch (error) {245if (isCancel(error)) {246console.log("Request was cancelled, ignoring error");247return null; // or some default value248}249throw error; // Re-throw non-cancellation errors250}251}252253// Usage254const controller = new AbortController();255const dataPromise = fetchData(controller.signal);256257// Cancel after 3 seconds258setTimeout(() => controller.abort(), 3000);259260const data = await dataPromise; // Will be null if cancelled261```262263### Advanced Cancellation Patterns264265Complex cancellation scenarios and patterns.266267**Usage Examples:**268269```typescript270import axios from "axios";271272// Cancellable request manager273class RequestManager {274private requests = new Map<string, AbortController>();275276async makeRequest<T>(key: string, url: string, config?: any): Promise<T | null> {277// Cancel existing request with same key278this.cancelRequest(key);279280// Create new controller281const controller = new AbortController();282this.requests.set(key, controller);283284try {285const response = await axios.get<T>(url, {286...config,287signal: controller.signal288});289290// Remove from tracking when complete291this.requests.delete(key);292return response.data;293} catch (error) {294this.requests.delete(key);295296if (axios.isCancel(error)) {297console.log(`Request ${key} was cancelled`);298return null;299}300throw error;301}302}303304cancelRequest(key: string): void {305const controller = this.requests.get(key);306if (controller) {307controller.abort();308this.requests.delete(key);309}310}311312cancelAllRequests(): void {313for (const [key, controller] of this.requests) {314controller.abort();315}316this.requests.clear();317}318}319320// Usage321const manager = new RequestManager();322323// Make requests324const users = manager.makeRequest("users", "https://api.example.com/users");325const posts = manager.makeRequest("posts", "https://api.example.com/posts");326327// Cancel specific request328manager.cancelRequest("users");329330// Cancel all pending requests331manager.cancelAllRequests();332333// Search with automatic cancellation334class SearchService {335private currentController?: AbortController;336337async search(query: string): Promise<any[]> {338// Cancel previous search339if (this.currentController) {340this.currentController.abort();341}342343// Create new controller for this search344this.currentController = new AbortController();345346try {347const response = await axios.get("https://api.example.com/search", {348params: { q: query },349signal: this.currentController.signal350});351352return response.data.results;353} catch (error) {354if (axios.isCancel(error)) {355console.log(`Search for "${query}" was cancelled`);356return [];357}358throw error;359} finally {360this.currentController = undefined;361}362}363}364365const searchService = new SearchService();366367// Rapid searches - previous ones get cancelled automatically368searchService.search("a");369searchService.search("ab");370searchService.search("abc"); // Only this one will complete371372// Timeout wrapper373function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {374const controller = new AbortController();375376const timeoutPromise = new Promise<never>((_, reject) => {377setTimeout(() => {378controller.abort();379reject(new Error(`Operation timed out after ${ms}ms`));380}, ms);381});382383return Promise.race([promise, timeoutPromise]);384}385386// Usage387try {388const data = await withTimeout(389axios.get("https://api.example.com/slow-endpoint"),3905000391);392console.log(data.data);393} catch (error) {394if (error.message.includes("timed out")) {395console.log("Request timed out");396}397}398399// Component cleanup pattern (React example)400class DataComponent {401private controller?: AbortController;402403async loadData() {404// Cancel previous request405if (this.controller) {406this.controller.abort();407}408409this.controller = new AbortController();410411try {412const response = await axios.get("https://api.example.com/data", {413signal: this.controller.signal414});415416// Update component state417this.setState({ data: response.data });418} catch (error) {419if (!axios.isCancel(error)) {420// Handle real errors421this.setState({ error: error.message });422}423}424}425426cleanup() {427// Cancel any pending requests when component unmounts428if (this.controller) {429this.controller.abort();430this.controller = undefined;431}432}433}434```435436### Cancellation with Promise.race437438Using cancellation with Promise.race for advanced patterns.439440**Usage Examples:**441442```typescript443import axios from "axios";444445// Race between multiple endpoints446async function fetchFromMultipleEndpoints(urls: string[]): Promise<any> {447const controller = new AbortController();448449const requests = urls.map(url =>450axios.get(url, { signal: controller.signal })451.then(response => ({ url, data: response.data, success: true }))452.catch(error => ({ url, error, success: false }))453);454455try {456// Return first successful response457const results = await Promise.all(requests);458const successful = results.find(r => r.success);459460if (successful) {461// Cancel remaining requests462controller.abort();463return successful.data;464} else {465throw new Error("All endpoints failed");466}467} catch (error) {468controller.abort();469throw error;470}471}472473// User-cancellable operation474async function longRunningOperation(onCancel: (cancel: () => void) => void): Promise<any> {475const controller = new AbortController();476477// Provide cancel function to caller478onCancel(() => controller.abort());479480const steps = [481() => axios.get("https://api.example.com/step1", { signal: controller.signal }),482() => axios.get("https://api.example.com/step2", { signal: controller.signal }),483() => axios.get("https://api.example.com/step3", { signal: controller.signal })484];485486const results = [];487488for (const step of steps) {489try {490const response = await step();491results.push(response.data);492} catch (error) {493if (axios.isCancel(error)) {494console.log("Operation cancelled by user");495return { cancelled: true, results };496}497throw error;498}499}500501return { cancelled: false, results };502}503504// Usage505let cancelOperation: (() => void) | undefined;506507const operationPromise = longRunningOperation((cancel) => {508cancelOperation = cancel;509});510511// User can cancel the operation512document.getElementById("cancelButton")?.addEventListener("click", () => {513if (cancelOperation) {514cancelOperation();515}516});517518const result = await operationPromise;519if (result.cancelled) {520console.log("User cancelled the operation");521} else {522console.log("Operation completed:", result.results);523}524```