XMLHttpRequest (legacy)
XHR — оригинальный AJAX API (IE5, 1999), предшественник Fetch; знание его API критично при работе со старыми кодовыми базами и при необходимости upload-прогресса, которого до сих пор нет в Fetch; спрашивают для понимания исторического контекста и при разборе поведения withCredentials.
// Базовый XHR, завёрнутый в Promisefunction xhrFetch(url, options = {}) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open(options.method ?? 'GET', url, true); // true = async
Object.entries(options.headers ?? {}).forEach( ([k, v]) => xhr.setRequestHeader(k, v) );
xhr.responseType = 'json'; // автоматический JSON-парсинг xhr.timeout = options.timeout ?? 10_000;
xhr.onload = () => xhr.status >= 200 && xhr.status < 300 ? resolve(xhr.response) : reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`)); xhr.onerror = () => reject(new Error('Network error')); xhr.ontimeout = () => reject(new Error('Timeout')); xhr.onabort = () => reject(new Error('Aborted'));
xhr.send(options.body ?? null); options.xhrRef?.(xhr); // опциональный доступ к инстансу });}// Upload с прогрессом — единственное реальное преимущество XHR перед Fetchfunction uploadWithProgress(url, file, { onProgress, onDone, onError } = {}) { const xhr = new XMLHttpRequest(); const form = new FormData(); form.append('file', file);
xhr.open('POST', url); xhr.withCredentials = true; // аналог credentials:'include'
xhr.upload.addEventListener('progress', e => { if (e.lengthComputable) onProgress?.(Math.round(e.loaded / e.total * 100)); }); xhr.upload.addEventListener('error', () => onError?.(new Error('Upload failed')));
xhr.onload = () => onDone?.(JSON.parse(xhr.responseText)); xhr.onerror = () => onError?.(new Error('Network error'));
xhr.send(form); return () => xhr.abort(); // возвращаем функцию отмены}
// Использованиеconst cancel = uploadWithProgress('/upload', file, { onProgress: pct => setProgress(pct), onDone: data => console.log('done', data),});// cancel() — прервать загрузку// XHR vs Fetch: таблица сравнения//// Feature XHR Fetch// ───────────────────── ───────────────────── ──────────────────────// API style Event callbacks Promise-based// Upload progress ✓ xhr.upload.onprogress ✗ (нет)// Download streaming частично (onprogress) ✓ ReadableStream// Abort xhr.abort() AbortController// Intercepted by SW ✗ ✓// Response types text/json/blob/arraybuf Stream / blob / json// Node.js (native) ✗ ✓ (18+)// HTTP/2 aware ✗ ✓//// Sync XHR (третий аргумент false) — устарел, блокирует main thread,// запрещён в Service Workers, генерирует предупреждение в DevTools:// xhr.open('GET', url, false); // НИКОГДА не использовать в productionИтог: XHR актуален только для upload-прогресса и поддержки legacy-кода; в новом коде используйте Fetch + AbortController.