Search
Write a publication
Pull to refresh
149
0.2
Зубашев Степан @faiwer

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

Send message
Мы с вами как будто с разных планет. Большинство моих знакомых айтишников закончили такие же препоганые университеты, как и я. И придерживаются того же мнения по поводу образования. Даже не большинство, если честно, а вообще все.
И в айти конечно встречаются люди с очень разным образованием. Но как правило оно у всех высшее в хороших ВУЗ-ах.

Учитывая, что подавляющее большинство ВУЗов ужасное, просто шараги раздающие корочки бакалавров, я не знаю откуда могут взяться такое вот правило. Может быть мы с вами по разному трактуем слово «хороший ВУЗ»?
Сегодня без хотя бы незаконченного высшего образования устроиться в хорошую компанию, где вы бы смогли расти, а не штаны протирать (эй программист — почини мне принтер) очень сложно.
Я ни разу ни на одно собеседование не таскал диплом. Ни один работодатель не задавал мне вопрос о том, что я заканчивал. Никому из них не было интересно моё «образование». Всех интересовали навыки в профильной сфере, опыт работы, используемые мной технологии, результаты тестовых заданий. А вот на образование всем было попросту плевать. С моими знакомыми IT-ми точно такая же ситуация. Наверное можно встретить заведение, ищущее того же программиста, но интересующееся его дипломом. Но это скорее исключение от невежества в отделе кадров.

если бы не несколько лекций в университете по ООП и сиплюсплюсам.
У меня был семестр с C++ и ООП (это был 1 предмет). Мы на весь семестр растянули тему «наследование», «полиморфизм» и «инкапсуляция» и т.д… И из лекции в лекцию твердили одно и тоже. Весь семестр. Ужасно. Ещё был предмет по алгоритмам и структурам данных. Вершиной мастерства в этом семестре для нас было написание quicksort-а. Вот зачем посещать университеты, тратить там 4-5 лет, если в конечном счёте, всё сводится к этому?

По большому счёту единственные предметы которые вменяемо велись и учили нас чему то не тривиальному ― курс предметов по работе сетей. Во многом за счёт талантливого педагога. Ещё неплохо преподавались предметы по рисованию диаграмм.

Мы определённо с вами живём на разных планетах :D
Прошу прощения, а вы где учились? Мне кажется в СНГ ВУЗов, в которых, айтишников учат чему то дельному, ужасно мало. А профильные предметы часто ведут бывшие студенты троечники этих же ВУЗов. Сами учебные программы безнадёжно устаревают к моменту начала их написания, молчу уж про факт преподавания.

Существуют и толковые ВУЗы. Но среди общего кол-ва мусорных заведений их сложно разглядеть. Да и попасть туда. Соглашусь с Zibx по поводу образования.
В разных языках, библиотеках разные реализации но идея одна, посмотрите как работают файберы.
Года 3 назад я пытался использовать node-fibers. Работало оно крайне препогано. Часто падало с сегфолтами, существенные проблемы с отловом ошибок, практически невозможно было это дело как то дебажить. Может быть сейчас стало лучше.
Вы меня запутали :)

Таким образом у нас получается много легковесных потоков в рамках одного системного потока, которые не жалко блокировать.
1. А как тут дело обстоит с гонками, дедлоками и пр.? Ведь если это легковесный поток, то это именно поток…
2. Что-то мне подсказывает, что заморозить кадр в async-методе, и, когда нужно, разморозить его обратно ― должно быть гораздо дешевле, нежели запуск отдельного потока, пусть и легковесного. Так ли это?

Или под «легковесным потоком» вы подразумеваете не настоящий поток, а его имитацию, которая только приостанавливает выполнение одного стека, возобновляя другой, стоящий в очереди? Если да, то чем это отличается от await?
например если в синхронном «дереве» вызова появится асинхронная ф-ия, то все дерево придется перепиливать на async/promise а так же все связанные части проекта, когда с корутинами этого ничего делать не нужно.
Правильно ли я вас понимаю, что синхронное «дерево» остаётся синхронным, но необходимая часть выполняется асинхронно? Если да, то как это может работать не блокируя текущий поток? В JS он 1, всё таки.
А ещё стоило бы добавить пункт позволяющий, выделив текстовую ссылку, перейти по ней. Т.е. если в тексте написано blabla…, но сий текст не обрамлён <a/>. В Chrome пункт в контекстном называется «Go To», в Opera тоже была такая возможность.
Чем-то жертвовать придется :)
Ага. Собственно об этом я и говорю. Так то да, await, async, yield это куда лучше, чем calback-hell или promise-hell :)
В идеале как то так:

return await list
      .filter(fn1)
      .map(fn2)
      //
      .invoke(fn3)
      .reduce(fn4)
      .groupBy(fn5)
      .map(fn6)
      .value();

Получится весьма не тривиально :) Хотя да, более, чем подъёмно.
А какие еще функции имеют смысл в асинхронном варианте?
Любые из тех, что принимают callback-и. А это половина библиотеки. Из самых часто используемых: .flatten (либо .flatMap), .reduce, .filter, .transform, .each. К примеру, в .filter может потребоваться некая проверка значения memcahed по ключу.

К тому же стоит учесть, что очень часто они применяются в цепочке, а не раздельно друг от друга.

А ещё вы ошибаетесь приравнивания .map, .each и Promise.all. Как минимум некоторые реализации .each-а умеют break-ать при return false.
так что тут я особой монструозности то и не вижу

return await list.asyncMap(fn1)
       .asyncFilter(fn2)
       .reduce(fn3)
       .some(fn4);

А так? :)
Спасибо. Возьму на заметку.
Ещё небольшой пример. Наверняка многие уже взяли за привычку использовать .forEach или _.each, для перебора массивов. Это удобнее, чем for-of потому, что мы не теряем индексы. В случае async-метода приходится использовать

for(let i = 0, n = list.length; i < n; ++ i)
{
  let el = list[i];
  // ...
}


Правда тут есть 1 решение. Дождаться пока node (я не использую babel) сможет вот так:

for(let [el, i] from iter(list))

Где iter будет костылём, который позволит перебирать массив массив на манер Map-а.

Честно говоря, я не слежу за ES6-7. В Array случаем уже не добавили возможность перебора for-of-м без потери индексов?
теперь понял вас. Логично, что затолкав в .map async-и мы получим промисы :) Но я имел ввиду что-то похожее на вот это:

return await list.asyncMap(someAsyncMethod);

Где asyncMap сам async-метод, который await-ми переберёт list someAsyncMethod-ом.

Но даже написав свой .asyncMap мы толком ничего не выиграем. Потому, что для того чтобы цепочка из вот таких вот async-монстро-функций заработала, придётся изрядно по… возиться. И всё равно получится что попало.
Пока код состоит из одной строки — да.
mayorov невероятно, оказывается существует Promise.all. Фантастика. Это всё меняет.

Прошу читать мои комментарии не по диагонали. Что вы будете делать в случае underscore, lodash или какой-бы то ни было ещё цепочке, основанной не на промисах? Если у вас каррирования, монады или ещё что-нибудь в таком духе?

Скорее всего забьёте и перепишите на не-функциональный подход. О чём я и говорю.
Даже если ее переписать, чтобы она не использовала arrow-функцию и использовала async, что будет работать технически, то мы в итоге все равно получаем массив промисов, как если бы вообще не использовали await в коде выше.

Гхм. Почему «массив промисов» а не массив результатов работы промисов?

Я понимаю, что товарищ faiwer говорил про «контекст», и ведь вроде как в стрелочных функциях тот же «this», что и за ее пределами

Прошу прощения, что запутал вас. Я вовсе не имел ввиду ни this, ни scope. Слово «контекст» я использовал в более широком значении. Имею ввиду то, что доступные возможности в рамках «тела» обычного function-а, generator-а и async function-а разные. В первом случае мы не можем применять ни await, ни yield; во втором только yield; а в третьем только await; Каждая стрелочная или обычная анонимная функция такой «контекст» прекращает, руководствуясь уже возможностями обычных функций. А так как async-функции и generator-ы это, по большому счёту, вообще не функции, то применять их в качестве обычных callback-ов мы не можем.

Надеюсь теперь стало яснее, что я имею ввиду :)
Ну собственно именно такое поведение и ожидается. Но на самом деле будет syntax error. Потому что await работает только в контексте async-function, а стрелочные функции — async-ами не являются.
А зачем писать свою реализацию .map() и прочих? Что мы хотим получить на выходе вот этой функции из примера?

Ну функция в примере сделала бы следующее (на самом деле будет syntax error):

async function test(list)
{
  var result = [];
  for(let el of list)
  {
    result.push(await someAsyncMethod(el));
  }
  return result;
}

Что делает someAsyncMethod не важно. Важно что он возвращает что-либо полученное асинхронно. В примере выше код стал более громоздким и менее читаемым. Функциональный подход часто бывает более наглядным.

Но пока у нас 1 map, нам по большому счёту плевать. А что если у нас типовая lodash цепочка методов? К примеру из 8 последовательных chain-вызовов? Придётся забить на lodash цепочку и написать всё в обычном стиле, через for-ы, if-ы и пр… А это, зачастую, бывает очень неудобным, в особенности после того как подсел на функциональный подход.

Т.е. получается что async-и и generator-ы НЕ позволяют писать асинхронный код также удобно, как и синхронный. И дело не только в том, что при более менее сложной логике async-и придётся плодить везде (что местами создаст определённые неудобства, потребует обёрток и пр. шаманств). А в том, что ограничения куда шире.

Но в любом случае, через async-ки и generator-ы писать сложный асинхронный гораздо удобнее.
«обещание» не очень хорошо звучит, отложенные объекы — лучше конечно но это чуть чуть другое.
Многократно встречал в сети promise-ы именно как «обещания». Можно сказать — уже привык к такому термину. Слух не корёжит. ИМХО, термин вполне подходящий.
Ну… Любой асинхронный код это дискомфорт, в той или иной мере. К тому, что нельзя будет магическим образом писать асинхронный код синхронно я был уже готов после генераторов. Одним из неприятных моментов является то, что javascript удобно использовать в функциональном стиле, но «контекст» async-а (или generator-а) теряется в анонимных методах. Т.е. вот так вот сделать нельзя:

async function test(list)
{
  return list.map(el => await someAsyncMethod(el));
}

Потому что await не будет работать внутри метода. Тоже самое и в генераторах (yield). Такие библиотеки как underscore, lodash и пр. располагают к использованию цепочек методов с callback-ами. Да даже нативные методы .map, .reduce, .some и пр. тут ставят нам грабли.

Конечно, какие-то конструкции для удобства можно написать самому, к примеру, свою универсальную реализацию .map, которой и метод и async сгодится. Но, ИМХО, проще смириться, что за любую асинхронщину нужно платить удобством.

Очень не люблю такие вот конструкции:
for(let i = 0, n = list.length; i < n; ++i)
{
  var el = list[i];
}

Но «for-of» лишит меня ключа, а .each yield (async) контекста. Что ж поделать… В любом случае это гораздо удобнее, чем callback-ый ад.

Information

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