Comments 24
Где тесты?
Если в цифрах, то размер axios составляет 371 Кб, а размер very-simple-fetch — 9.33 Кб.Но ведь это всё gzip'ом отдают. В таком случае он вряд ли будет больше 10 kB.
Вопрос - fetch() сложный? Куда уж проще... Ладно колбеки в XMLHttpRequest не нравились, вот вам промис готовый, нет надо лишний траффик, чтобы обертку накатить.
Ну ладно, а в чем преимущество перед наивным fetch ()? Вообще не понял
Если говорить про axios, то преимуществ ощущается несколько:
Единый код для node и browser
Возможность установки настроек для instance. Вроде baseUrl, заголовков, которые должны передавать с каждым запросом (тот же Authorization)
Есть interceptors.
Можно это сделать самому вокруг того же fetch, что и сделал автор статьи для своего проекта.
simpleFetch.cancel()
очень странно работает в случае нескольких параллельных запросов. Получается, что он отменит их все сразу. Правильнее было бы сделать какой-то более гранулярный контроль.
И еще пара рационализаторских предложений:
Для собирания baseUrl можно было взять нативное API:
new URL(options.url, baseUrl)
Для параметров тоже есть нативный URLSearchParams
P.S. и совсем маленькое замечание – сократили вы бы пост в два раза, в ценности бы он совсем не потерял. Не обязательно комментировать каждую строку кода, можно только про самое важное рассказать.
Спасибо за рационализаторские предложения.
2) Поправил
if (options?.params) {
url = `${url}?${new URLSearchParams(options.params)}`
}
1) new URL() не будет работать в случае передачи url без ведущего /, а также в случае передачи в качестве url параметров строки запроса.
3) добавил возможность безопасной отмены параллельных запросов:
// будет отменен последний отправленный запрос
simpleFetch.cancel()
// отправляем запрос
simpleFetch(url)
// извлекаем его id
const { currentRequestId } = simpleFetch
// отменяем этот запрос
simpleFetch.cancel(currentRequestId)
Добавили возможность отмены запросы и сделали ошибку в коде.
У вас есть подсветка в редакторе?
?
const generateRequestId = () => {
const requestId = Math.random().toString(16).slice(2)
if (simpleFetch.abortControllers[requestId]) {
return getRequestId()
}
simpleFetch.abortControllers[requestId] = new AbortController()
simpleFetch.currentRequestId = requestId
return requestId
}
Где в коде функция getRequestId?
А мне, новичку, с опытом 0 и даже минус очень нужны такие комментарии.
Полезно (и просто) добавить нормальный chaining, вместо затычек вроде вашего authToken.
Патч выше с currentRequestId небезопасен, лучше уж добавить событие onRequest и создавать его там. Что-то вроде
const api = fetcher({...options, authToken, baseUrl}, request => {
request.on(2000, request.cancel)
})
await api.get('data')
Скажите, а рассматривали ли вы Redaxios? https://github.com/developit/redaxios
Никогда не понимал зачем люди тащат в 2021г в свои проекты axios
или подобные либы. В каждом проекте одна из первых задач, которую я решаю это создание двух слоёв архитектуры:
- Слой
http
(название от балды), где зарыта вся специфика работы с конкретным бакендом. JSON | XML? JWT? Кастомные заголовки? Какой формат у ошибок? CORS? Есть ли специфические заголовки в response? И так далее. Ключевой момент — оно всегда одинаковое для адекватного сервера (если проект пишет не безумец). Так что это слой неизбежен и предельно очевиден - Слой
api
, который под капотом работает с вышеописаннымhttp
. Этот слой ничего не знает о вашей бизнеслогике. Просто служит прослойкой между сервером и вашим приложением. Здесь можно подключить нужные io-ts валидаторы. Здесь можно трансформировать данные из какого-нибудь неудобного формата в удобный и наоборот. Здесь можно запустить несколько запросов в параллели. Но самое главное что вся эта мишура лежит внутри этого слоя и не выглядывает наружу. Т.е. здесь будет условныйexport const apiLoginUser = (userName: string, password: string): Promise<AccessTokens/>
. Никакой сетевой требухи. Этот же слой можно mock-ать для тестов и обходится вообще без сервера, если нужно.
В итоге в приложении используются уже максимально упрощённые promise-based методы. Никаких fetch/axios/whatever обвязок. И тут возникает главный вопрос — а зачем при такой архитектуре axios
? Чтобы не писать в единственном месте в приложении .then(response => response.json())
и сделать проверку на .statusCode
? Серьёзно?
Было бы интересно послушать противоположное мнение.
Для сравнения ohmyfetch
Начал смотреть код снизу - и сразу в первом же методе, видимо, пропущен method: 'DELETE'
при передаче одного объекта опций.
Задать методы вроде .delete
и подобных можно чем-то вроде
const createMethod = (method, hasBody) => (...args) => simpleFetch({
method,
url: typeof args[0] == 'string' ? args.shift() : undefined,
body: hasBody && args.shift(),
...args.shift(),
})
simpleFetch.get = createMethod('GET')
simpleFetch.post = createMethod('POST', true)
simpleFetch.update = createMethod('PUT', true)
simpleFetch.delete = createMethod('DELETE')
и это сэкономит строк 40.
Использование конструктора и объектов URL
сильно упростит и улучшит работу.
Глобальные настройки - зло. Предположим, данную библиотеку используете не только вы, но и кто-то ещё, тоже задает baseUrl
и authToken
и все ломает. У axios
на такой случай есть разные инстансы.
JavaScript: как из Fetch сделать Axios?