Одним из недостатков изпользования AJAX в вебе долго оставалось вот это - XMLHttpRequest - API не предназначенное для такого использования. Было много элегантных оберток вокруг XHR, но всегда казалось, что можно лучше.
XMLHttpRequest
XHR чересчур сложен на мой взгляд. Да и в целом непонятно, почему XML написано заглавными, а Http кэмел-кейсом. Но это не важно, вот как выглядит его использование:
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e) {}
}
}
request.open('GET', 'http://test.com/ajax-endpoint', true);
request.send(null);
Конечно многочисленные библиотеки и фреймворки значительно упращали работу с этим... вот этим сверху.
fetch
Функция fetch доступна сейчас в глобальном объекте window, и первым аргументом туда передается адрес:
// url (обязательно), options (опционально)
fetch('http://test.com/ajax-endpoint', {
method: 'get'
}).then(function(response) {
}).catch(function(err) {
// Ошибка :(
});
Как и большинство современных апи, fetch API использует JavaScript Promises для работы:
fetch('http://test.com/ajax-endpoint').then(function(response) {
}).catch(function(err) {
// Ошибка :(
});
// Чуть более "продвинутое" использование
fetch('http://test.com/ajax-endpoint').then(function(response) {
return //...
}).then(function(returnedValue) {
// ...
}).catch(function(err) {
// Ошибка :(
});
Request Headers
Возможность добавить и/или изменить заголовки важная часть совеременных запросов. Для этого необходимо всего-лишь использовать new Headers():
// Создаем пустой объект заголовков
var headers = new Headers();
// Добавим парочку
headers.append('Content-Type', 'text/plain');
headers.append('X-My-Custom-Header', 'CustomValue');
// Вот гетеры и сетеры
headers.has('Content-Type'); // true
headers.get('Content-Type'); // "text/plain"
headers.set('Content-Type', 'application/json');
// Удаление заголовка
headers.delete('X-My-Custom-Header');
// Значения при инициализации
var headers = new Headers({
'Content-Type': 'text/plain',
'X-My-Custom-Header': 'CustomValue'
});
Можно использовать методы append
, has
, get
, set
и delete
для работы с заголовками. Для того что бы работать с заголовками можно использовать Request :
var request = new Request('http://test.com/ajax-endpoint', {
headers: new Headers({
'Content-Type': 'text/plain'
})
});
fetch(request).then(function() { /* обработка ответа */ });
Request
Request - это часть запроса в fetch. Передавая Request в fetch, можно использовать расширенные возможности запроса:
method
- GET, POST, PUT, DELETE, HEADurl
- адрес запросаheaders
- объект заголовковreferrer
- отправитель запросаmode
- cors, no-cors, same-origincredentials
- надо ли отправлять куки вместе с запросомredirect
- follow, error, manualintegrity
- integrity valuecache
- тип кэширования (default, reload, no-cache)
Пример использования Request:
var request = new Request('http://test.com/ajax-endpoint', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
});
// А теперь давайте используем!
fetch(request).then(function() { /* обработка ответа*/ });
Только адрес (URL) является обязательным.Все свойства становятся неизменяемыми после создания запроса. Важно помнить, что у Request есть метод clone
, который придется кстати, когда надо использовать fetch
внутри Service Worker API
, - Request - это поток (stream), а его надо клонировать для потправки в fetch.
fetch также может создавать запрос самостоятельно:
fetch('http://test.com/ajax-endpoint', {
method: 'POST',
mode: 'cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain'
})
}).then(function() { /* обработка ответа */ });
Response
Метод then
возвращает объект Response
, но также можно самостоятельно создать оюъект Response. Вот что можно настроить:
type
- basic, corsurl
useFinalURL
- Boolean если адрес будет конечнымstatus
- статус (200, 404 и т.д.)ok
- Boolean для успешной обработки (статусы 200-299)statusText
- статус ответа (например OK)headers
- объект заголовков.
var response = new Response('.....', {
ok: false,
status: 404,
url: '/'
});
fetch('http://test.com/ajax-endpoint')
.then(function(responseObj) {
console.log('status: ', responseObj.status);
});
Response также предоставляет методы:
clone()
- клонирование объекта Response.error()
- возвращает новый объект Response содержащий ошибку.redirect()
- создает новый ответ с другим адресом.arrayBuffer()
- возвращает промис содержащий ArrayBuffer.blob()
- возвращает промис содержащий Blob.formData()
- возвращает промис содержащий объект FormData.json()
- возвращает промис содержащий JSON.text()
- возвращает промис содержащий USVString (текст).
Работа с JSON
Пример запроса, возвращающего JSON:
fetch('http://test.com/ajax-endpoint').then(function(response) {
// Конвертация ответа в JSON
return response.json();
}).then(function(j) {
// А здесь уже объект JavaScript
console.log(j);
});
Обработка Basic Text/HTML ответов
JSON - это самый желанный формат данных, но часто приходится работать с HTML или текстом:
fetch('/next/page')
.then(function(response) {
return response.text();
}).then(function(text) {
// <!DOCTYPE ....
console.log(text);
});
Обработка Blob ответов
Если хочется например загрузить изображение через fetch
, то:
fetch('http://test.com/flowers.jpg')
.then(function(response) {
return response.blob();
})
.then(function(imageBlob) {
document.querySelector('img').src = URL.createObjectURL(imageBlob);
});
Отправка данных с Form Data
Еще один частый пример использования AJAX - отправка данных из формы:
fetch('http://test.com/ajax-endpoint', {
method: 'post',
body: new FormData(document.getElementById('comment-form'))
});
Ну а если надо отправить JSON:
fetch('http://test.com/ajax-endpoint', {
method: 'post',
body: JSON.stringify({
email: document.getElementById('email').value,
answer: document.getElementById('answer').value
})
});
Очень просто и очень удобно!