Pull to refresh
99.7
Karma
1
Rating
Зубашев Степан @faiwer

frontend-программист

  • Followers 51
  • Following 7

Async/await в TypeScript

const runAsyncFunctions = async () => {
    try {
        const employees = await fetchAllEmployees(baseApi)
        Promise.all(
            employees.map(async user => {
                const userName = await fetchEmployee(userApi, user.id)
                const emails = generateEmail(userName.name)
                return emails
            })
        )
    } catch (error) {
        console.log(error)
    }
}

вы тут await перед Promise.all забыли. Без него всё насмарку.


upd1. и ещё забыли return, иначе какой смысл писать return emails.
upd2. и скорее всего нужен .flat() а то у вас странный список email[][] получается :-) переменная названа криво, т.к. email один, должно быть email (без s).

React: разрабатываем хук для загрузки дополнительных данных

Перечитай внимательно комментарий выше. Использование useRef для реактивных значений — грубая ошибка. Ибо это бомба замедленного действия. Тот самый скользкий тип багов, которые потом тяжело воспроизводить и выяснять причины странного поведения. Один из самых дорогостоящих видов багов для бизнеса.


Да я вижу, что смена items всё равно вызывает ререндер, но на такие вещи полагаться нельзя. Ни в коем случае. Минимальный рефакторинг в будущем, когда человек не будет иметь всей картинки костылей в голове, легко поломает этот "код". И да, текущее "случайно" работающее поведение это как раз костыль. Красный флаг.


Результатом стал многократный повторный рендеринг

Вот чтобы таких вещей не было надо вникать в то как хуки работают, какие задачи они выполняют, и каков вообще hook way в реакте. Судя по всему (по твоим ответам и коду в статье) ты пока пишешь "на ощупь". Отсюда и типовые ошибки и типовые костыли. Серьёзно, я не хочу обидеть, просто это видно издалека.


hasPrev и hasNext также были реактивными

Вот это тоже грубая ошибка. Которую, насколько я понял, ты уже усвоил. Тут действует простое правило — всё что можно посчитать на основе уже существующих данных — не нужно хранить в стейте. Максимум мемоизировать (useMemo), если вычисления тяжёлые. Причина банальна — ручная синхронизация = новый источник багов = дорого. В твоём случае ещё и rerender-ы.


многократный повторный рендеринг

Нет смысла, оптимизация будет преждевременной

За что боролся на то и напоролся. Когда пишешь core-вещи, т.е. обобщённый многократно переиспользуемый код (а твой хук как раз из таких), то это должна быть вылизанная до мелочей оптимизированная штука. Иначе — руки прочь из core части. Даже вопроса такого не должно возникать.


Я бы не сказал, что "хранить все в одном объекте" всегда проще

А где я сказал "всегда"? У нас на 80к строк кода всего несколько useReducer. У тебя как раз такой случай, когда useReducer упрощает понимание кода, убирает лишние рендеры, легко scale-уется в случае сложных доработок. То, что доктор прописал. Да ещё и все переменные тесно связанные между собой. ​Особенно если учесть что в настоящем боевом коде этот хук будет куда сложнее, когда полезут corner case-ы.


  1. Возможно.

Не возможно, а точно, я тебе говорю. На этапе system design такой ответ это красный флаг и "мы вам перезвоним". Тебе завтра потребуется подключить этот хук в другую часть приложения где более сложная работа с URL (или просто другая) и тебе придётся выпиливать всё до последней буквы. Да даже просто наличие на странице сразу двух постраничных виджетов (или списка списокв) и "приехали".


А причина банальная — это не задача для хука который занимается вызовом асинхр. метода который подтягивает данные согласно постраничной навигации. "low in coupling and high in cohesion" — вот главная мантра любой архитектуры. Из неё автоматически вытекает что не должно быть таких пучков которые умеют во всё сразу, особенно как-то конкретно (?page= в любой URL игнорируя рутинг приложения).

Одна задача с собеса

Разве у Promise именно "своя" очередь? Мануалы вроде говорят что они используют очередь микротасок.

Не совсем своя. Я просто не стал вдаваться в детали. Количество и состав очередей зависит от платформы. На мой взгляд эти нюансы мало кому важны, главное просто знать, что эта очередь "микротасок" есть, и с чем её едят. Чтобы, например, не уйти в вечный loop.


А в вашем примере макротаска заканчивается выделением микротаски и микротаска сразу стартует, давая условный 0.

Всё правильно.

Одна задача с собеса

Не очень понял почему там должен быть не 0

Суть в том что у promise-ов своя приоритетная (над обычной) асинхронная event-loop очередь. Поэтому там 0. Разгадка в этом. В то время как у setTimeout(,0) и даже у requestAnimationFrame это не так. По сути аналог, ЕМНИП, есть в nodejsprocess.nextTick.


ЕМНИП, то с её помощью можно даже повешать браузер\nodejs-процесс.

React: разрабатываем хук для загрузки дополнительных данных

А лучше под <spoiler/>, чтобы не только главная не прыгала, но ещё и сама страница статьи.

Размышления об идеальной архитектуре для JavaScript

/** @type {<P, R>(func: (data: P) => R) => (data: Option<P>) => Option<R>} */
export const map = func => data => data !== undefined ? func(data) : undefined

// vs

type Map = <P, R>(func: (data: P) => R) => (data: Option<P>) => Option<R>;
export const map: Map = func => data => data !== undefined ? func(data) : undefined

Очевидно же, что 2-е лучше. И дело даже не в том, что у вас подсветка синтаксиса (vsCode и в комментарии всё подсветит). А в том что теперь TS компилятор упадёт если вы что-то сломаете в этом файле.


JS-Doc типы нужны для двух вещей:


  • а) у вас тонна JS кода, которую надо постепенно переводить на TS. И часто вы просто не можете это сделать быстро, а уже нужно чтобы наружу от JS файлов торчали нормальные типы. Тут комментарии и спасают. TS верит вам на слово и нормальный перевод с JS на TS вы осуществите тогда, когда будет на то возможность.

  • б) вы пишете что-то примитивное на 10 минут — proof of concept, и не хотите эти 10 минут ковыряться со всякими tsConfig.json и npm. И например хотите просто скопировав код сразу запустить его в браузере.

Просто так же писать JS + JsDoc вместо TS кода — это какой-то особенный вариант садомазохизма.


Касательно FP стиля для типов — оно тоже удобно, но я думаю никто из TS разработчиков не перешёл бы на такой формат, если бы он был ультимативным. Удачным вариантом была бы возможность использовать и то и другое по ситуации.

Одна задача с собеса

Всё так. Но давайте мыслить дискретно позитивно! :-)

Одна задача с собеса

а зачем вообще появился throttle?

Нуууу… Скролл бывает очень дробным. Скажем проскроллил тачпадом на 15px, браузер вызвал 15 событий. Из которых 10 попало в один кадр. 10 раз был изменён textContent, а он, к примеру 3 раза поменял layout страницы (не моноширинный шрифт). Где-то плачет Грета и считает углеродный след. Но в целом согласен.

Одна задача с собеса

C requestAnimationFrame результат может быть даже лучше.


А если сделать Promise.resolve().then(fn) то вообще ноль покажет (это кстати довольно хардкорный JS вопрос на собесах). Но это уже немного не в тему, да :)

React: разрабатываем хук для загрузки дополнительных данных

Когда вместо SELECT ... OFFSET {(page - 1) * limit} LIMIT {limit} используются более сложные схемы. Например берётся items.last().createdBy.toUnixTime() и возвращается в качестве курсора\якоря\как-угодно-можно-назвать. А на сервере WHERE createdBy >= {cursor}.


Это не даёт вам общего числа "страниц", зато сильно улучшает выборку данных, когда просматриваемый список элементов не статичен. Из-за постраничной навигации вы получаете дублирующие элементы или вообще теряете часть. Просто потому что между кликаниями по страницам кто-то меняет выборку.

Одна задача с собеса

Не соглашусь. Можно смело вызывать setNumber на уже мёртвом компоненте. Ничего не случится. Кажется в свежей версии React убрали (или вот вот уберут) этот warning, из-за бесконечных ложно-позитивных результатов.


Но вот если там происходит, например, отправление формы и по успеху делается роутинг типа такого

ИМХО, только в таком случае и стоит так поступать. А более простой код калечить не стоит. YAGNI.


P.S. мы написали простенький useIsUnmounted: () => (): boolean для таких целей. Компактнее и нагляднее получается. Плюс можно переиспользовать для нескольких callback-ов и effect-ов.


const isUnmountFn = useIsUnmounted();

useEffect(() => {
  whatever().then(() => {
    if (isUnmountFn()) return;
    // do staff
  });
}, [/**/);

Но избегать обыкновенный useState этим — из пушки по воробьям. Лаконичность и простота кодовой базы сильно важнее.

Одна задача с собеса

На месте интервьювера я бы спросил что такое 37. Ожидал бы, что человек после этого вопроса скажет, что magic numbers это плохо и вынесет это в константу. А заодно даст внятный комментарий. И тут самое интересное — почему 37? Может лучше 16.7 (1/60 секунды).


P.S. забыл дописать — нет обработки ошибок асинхронного запроса (хотя бы console.error)

React: разрабатываем хук для загрузки дополнительных данных

return {
  currentPage: currentPage.current,
  allPages: allPages.current,
}

Вот тут грубая ошибка. Либо у вас это реактивный state, и тогда вы можете вернуть это из хука наружу. Либо это не реактивный стейт, и тогда render vDom древа ни в коем случае не должен от таких значений зависеть. Т.е. не используйте useRef для рективных вещей. Для этого есть useState и useReducer (ну и всякие mobX и прочие внешние сторы).


Возможно у вас сейчас этот баг никак не проявляется ввиду того, что помимо currentPage и allPages обновляется что-нибудь ещё и соответственно необходимый render всё равно происходит. Но на такие вещи точно нельзя полагаться. Это скорее из области "случайно работает".


Если вы используете useRef вместо useState только чтобы избежать лишних ререндеров — useReducer или unstable_... вам в помощь. А сейчас вы ходите по минному полю.

React: разрабатываем хук для загрузки дополнительных данных

Пара советов:


  1. Обратите внимание на useReducer. Проще хранить всё в одном объекте (все эти page и пр. штуки, которые вы почему-то храните в ref-ах), и менять разом.
  2. Ещё стоит пресекать race-condition. Если проект большой и важный, то без этого вообще никак. Правда это само по себе — тема для целой статьи.
  3. Обработку ошибок делать более централизовано. console.error-ы раскиданные по коду это плохо. И вообще хорошо бы уметь возвращать её (ошибку) из хука.
  4. Кеш лучше делать опциональным (или вообще не делать), т.к. это далеко не всегда желаемое поведение.
  5. Ещё я бы выпилил всё что касается URL из этого хука, т.к. вы таким образом нарушаете принцип ограниченной ответственности. Такие вещи должны быть извне.
  6. Не увидел никакой мемоизации. Это странно для хука базового назначения.

Мы используем похожую, но кратно более сложную схему.


P.S. ещё можно посмотреть в сторону отказа от page, в пользу курсоров.

Old Skull — фронтенд-фреймворк из альтернативной вселенной

Good. А если не убирать пустые пробелы и перенос строки перед <div class тоже работает?


Есть как подсветка локальных переменных

Тут как раз всё просто — это же интерполяция. Так любой редактор сможет. А вот воспринять автоматически это как HTML без бубнов, возможно, только Idea.

Old Skull — фронтенд-фреймворк из альтернативной вселенной

А какие, если не секрет? WebStorm?


vsCode

Лучшие стратегии разработки фронтенда в 2022 году

Ожидал от статьи какой-то конкретики. Ведь все итак знают, что можно вынести часть логики в worker-ы, но потом встаёт проблема коммуникации между основным thread-ом и worker-ом. И вот тут дилемма — а как организовать это всё так, чтобы потери на обмен не превышали выгоды от выноса логики в worker-ы. Вот это было бы интересно почитать. А в статье имеем много-много воды и красивых диаграмм. Ух.

Лучшие стратегии разработки фронтенда в 2022 году

посмотри Климова

Не стоит. Он в своей нелюбви к Typescript давно уже перестал быть объективным. Его категоричность давно перешла грань здравого смысла. Особенно когда в одном видео он топит за то что типы не нужны, пишите на JS + тесты, а в другом давайте писать на sound re-script, ибо "всё или ничего". Либо язык без типов, либо сразу sound. Климов — просто TS хейтер. TS есть за что ругать, но Климов воюет не туда.


Лично я с ним только в одном согласен — писать на TS хорошо могут немногие. Язык богат на возможности, но задействовать их с пользой бывает весьма нетривиально. Уровень входа в язык высокий.

Лучшие стратегии разработки фронтенда в 2022 году

Множество стандартных библиотек тоже не типизировано

Если брать не количественно, а по популярности\частотности их использования, то почти всё типизировано. Это как сказать что большая часть интернета до сих пор на HTTP, что отчасти правда, если считать число сайтов. Но если учесть долю на рынке, то всё наоборот (посмотрите среди открытых вкладок сколько из них не HTTPS). Такая же ситуация и с типами.


Проблема типов "стандартных" библиотек не в том, что типов нет, а в том что часто они посредственного качества. Скажем не все методы описаны, не все объекты полны, местами стоят any и т.д..


можно будет перестать использовать any

Его и сейчас нет необходимости использовать. В тех редких случаях когда типов нет вообще, они пишутся руками в d.ts файлах в кратчайшие сроки, т.к. не требуется покрывать всю библиотеку. Достаточно только того API что вы используете в своём проекте.

Современный Frontend: проблемы и пути решения. Пишем React-like приложение со строгой типизацией без сборщиков

Понятно, спс. Да, у нас очень много алгебры типов, поэтому ломается в очень неочевидных местах. Нужен весь граф связей, которых никаким find usages не получить. Да и пробегать всё это вручную то ещё удовольствие.

Information

Rating
1,236-th
Location
Алматы (Алма-Ата), Алма-Атинская обл., Казахстан
Date of birth
Registered
Activity