
В этом уроке мы с вами разберем что такое fetch и как он отличается от XMLHttpRequest. Fetch - это улучшеный XMLHttpRequest, который по умолчанию использует промисы и более простое и чистое API.
Следует сразу заметить, что fetch не поддерживается всеми браузерами. Например в IE 10-11 он не работает. В Safari он работает с версии 10. Конечно для него есть полифил, который использует XMLHttpRequest с старых браузерах.
Для того, чтобы обращатся на сервер за данными, давайте создадим API с тестовыми данными с помощью сервиса mocky.io.
Вот у меня есть JSON данных
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
{
"userId": 1,
"id": 3,
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
}
]
Вставляем его в body запроса и в advance mode выбираем
Access-Control-Allow-Origin:*
Для того, чтобы любой домен мог обращатся к этому API.
Нажимаем Generate response и получаем ссылку на наш API.
Теперь давайте напишем запрос с помощью fetch, который позволит нам получить данные.
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(function (response) {
console.log('response')
})
Один из нюансов в fetch, что мы не получаем сразу в response данные, а Stream-обьект. Это значит, что мы должны наш response парсить, для того, чтобы получить данные.
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(function (response) {
response.json().then(function (data) {
console.log('data', data)
})
})
Здесь мы используем метод .json, чтобы парсить ответ как json. Результат вызова .json тоже является промисом, поэтому мы должны писать then, в котором мы получим результат. Если мы посмотрим в браузер, то у нас в консоли вывелись данные.
Этот код можно написать чуть чище, разбив на 2 then конструкции и избежав глубокой вложенности
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(function (response) {
return response.json()
})
.then(function (data) {
console.log('data', data)
})
Если мы посмотрим в браузер, то наш код работает точно также.
В получении данных часто возникают ошибки и их нужно как-то обрабатывать. В fetch с этим есть нюансы. Обычно думаешь, что если написать .catch, то отловишь любую ошибку.
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(function (response) {
return response.json()
})
.then(function (data) {
console.log('data', data)
})
.catch(function (error) {
console.log('error', error)
})
Мы с вами добавили catch, но с спецификации fetch сказано, что туда попадают только network ошибки. То есть связанные с сетью. Например, когда запрос отваливается по таймауту.
Если мы хотим отловить обычные ошибки, их нужно обрабатывать в первом блоке .then. И так как мы работаем с промисами, то мы можем их резолвить и реджектить когда хотим
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(function (response) {
if (response.status !== 200) {
return Promise.reject(new Error(response.statusText))
}
return Promise.resolve(response)
})
.then(function (response) {
return response.json()
})
.then(function (data) {
console.log('data', data)
})
.catch(function (error) {
console.log('error', error)
})
Мы добавили еще один блок с resolve и reject, который позволяет сделать нашу работу с fetch правильной. Ни один из следующих then не выполнится при ошибке, а мы сразу попадем в catch.
Теперь мы можем вынести 2 функции из этой цепочки, так как они у нас будет одинаковые во всех использованиях fetch.
var status = function (response) {
if (response.status !== 200) {
return Promise.reject(new Error(response.statusText))
}
return Promise.resolve(response)
}
var json = function (response) {
return response.json()
}
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30')
.then(status)
.then(json)
.then(function (data) {
console.log('data', data)
})
.catch(function (error) {
console.log('error', error)
})
Если например бы хотим сделать POST запрос, то там достаточно указать method post. Также мы можем добавить body, которое мы хотим передать в запросе.
var status = function (response) {
if (response.status !== 200) {
return Promise.reject(new Error(response.statusText))
}
return Promise.resolve(response)
}
var json = function (response) {
return response.json()
}
fetch('http://www.mocky.io/v2/5944e07213000038025b6f30', {
method: 'post',
body: 'test=1'
})
.then(status)
.then(json)
.then(function (data) {
console.log('data', data)
})
.catch(function (error) {
console.log('error', error)
})
Как мы видим, fetch намного более гибкий чем XMLHttpRequest. Из-за использования промисов он позволяем нам комбинировать код, как нам нужно.
И хоть много компаний уже испольют fetch я хочу озвучить ряд минусов, которые я вижу.
Есть ли у меня решение на эти вопросы? Я предпочитаю использовать библиотеки superagent или axios, где все эти вопросы уже решены и нужно писать мимимум кода. Поэтому если у вас есть выбор, какую технологию использовать, то попробуйте эти библиотеки.
Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.