Comments 56
У меня такое ощущение, что callback hell — это специальный, восьмой круг. Специально для тех, кто «статику пыхой отдает».
+47
Возможно. Однако у меня не было на тот момент времени писать еще и обвязку типа реги/логина, логики доступа к комнатам и их рендера на js'e. Так что я просто взял ранее написанные пыхорешения, встали как влитые.
Сейчас-то все, само собой, на одной платформе работает.
Сейчас-то все, само собой, на одной платформе работает.
+2
Я второй год на Scala Days продвигаю тему, что разработчики Play — бакланы :) В прошлый раз задавал им вопросы и было много лулзов. Spray куда лучше, хотя скорее не для сайтиков, а для http. Хотя шаблонизатор туда очень просто влезает и с WS не думаю, что какие-то проблемы. Правда чуваки используют scalaz и IDEA иногда не очень понимает, что происходит :)
0
Ну хз, сейчас мне фуллстек фв как-то приятнее.
Конечно, можно взять http(s) сервис, натянуть шаблонизатор и любимую либу к бд, собрать свой лего. Но опять же — деплой с нуля руками пиши, sbt ковыряй. Выполнимо, не суперсложно, но зачем?
Кстати, плей переезжает/переехал на spray, если мне не изменяет память.
Конечно, можно взять http(s) сервис, натянуть шаблонизатор и любимую либу к бд, собрать свой лего. Но опять же — деплой с нуля руками пиши, sbt ковыряй. Выполнимо, не суперсложно, но зачем?
Кстати, плей переезжает/переехал на spray, если мне не изменяет память.
0
Ну, как бы, api first.
Вот, чтобы клиентский api был удобен, без магии. Да и вроде в Typesafe Reactive Platform для работы с БД Slick положен, а тут по дефолту не он, что странно.
Переехали на spray-io, клиентский api опять же свой.
Может правда я покастомнее люблю, но мы с пацанами когда выбирали, как-то сразу всем spray больше понравился.
Вот, чтобы клиентский api был удобен, без магии. Да и вроде в Typesafe Reactive Platform для работы с БД Slick положен, а тут по дефолту не он, что странно.
Переехали на spray-io, клиентский api опять же свой.
Может правда я покастомнее люблю, но мы с пацанами когда выбирали, как-то сразу всем spray больше понравился.
0
Я могу взять и сделать в одну строку из десятка Future один единственный и ждать его исполнения.
Также как и в JS'ике.
Вообще можно было с самого начала написать с оглядкой на грядущий «callback hell».
Или же сразу посмотреть в сторону bacon.js, Rx.
Если ещё есть время — можно поиграться с websockets в эрланге, думаю будет интересно ;)
+3
Да я с Iteratee итак навеселился вдоволь. Ребята вдруг решили, что кто-то по wsу будет гонять тонны мегабайт, поэтому СРОЧНО нужно делать асинхронные итераторы/энумераторы с возможностью вытягивать ограниченное количество данных. Благо, от стандартных on/push не отказались до конца.
Вот теперь хочу перенести WS соединения на акторы в новой версии фреймворка.
Если честно, приелось писать одно и то же ради писанины :) Хочу уже запустить корабль в плавание.
Вот теперь хочу перенести WS соединения на акторы в новой версии фреймворка.
Если честно, приелось писать одно и то же ради писанины :) Хочу уже запустить корабль в плавание.
+2
ОФФТОП: пейстбин для совместного кодинга полно, я лично юзаю collabedit.com/
0
Может это все ваши энергетики, но подача мне понравилась, легко читать, когда постоянно что-то эмоциональное в тексте происходит
+14
github.com/caolan/async#waterfall спасает от ада кобеков
+4
От
callback hell
так же отлично спасают промисы.+6
Для колбэков мне придется писать обертку, которая либо будет считать количество окончившихся функций, либо станет полноценным Deferred/Promise. Да, да, я знаю про существование подобных библиотек для JavaScript. Но это же просто раздутые обертки к тем самым колбэкам.
Я к тому, что нормальных нативных решений на тот момент не было. Не знаю, как там сейчас промисы в ECMA поживают.
А все подобные либы и решения — обвязки, костыли, пусть иногда и красивые, но все же в парадигму языка вливаются не на 100%.
0
А теперь, если вы с полученными знаниями перепишете все заново на JS, используя аналогичные инструменты и библиотеки — получится ничуть не хуже.
1) Хорошая архитектура на языке X всегда лучше плохой на языке Y.
2) Scala + Play vs. raw JS? Что мешало использовать JS-фреймворки?
3) Любая success-story вида «переписал с языка X на язык Y» неинтересна: второй подход к тому же снаряду всегда получится лучше, ибо набиты шишки, и четко известно, что надо писать.
1) Хорошая архитектура на языке X всегда лучше плохой на языке Y.
2) Scala + Play vs. raw JS? Что мешало использовать JS-фреймворки?
3) Любая success-story вида «переписал с языка X на язык Y» неинтересна: второй подход к тому же снаряду всегда получится лучше, ибо набиты шишки, и четко известно, что надо писать.
+1
Написал бы я сейчас на JavaScript лучше, чем тогда? Несомненно. Это, возможно, даже выглядело и работало бы попроще. Опыт в решении задач одного типа — это опыт, его не пропьешь.
Однако есть еще одно но, я его в статье не упомянул, так как ну ооочень субъективно. Я получаю удовольствие от Scala, с ее статической типизацией внутри спокойнее как-то что ли. От JS я страдаю, поэтому даже нынешний фронтэнд писал на coffee + angular
0
Я вовсе не защищаю JS как язык. Сравнивать тщательно спроектированную Scala с написанным в спешке за 10 дней JS — глупо, да и потроллить nodejs-хипстеров я сам в первых рядах. Я всего лишь о некорректности сравнения. Да, то, что есть в Scala из коробки, в JS достигается дополнительными инструментами, но это же не имеет никакого значения для достижения результата.
Angular — это прекрасно; когда приходится дописывать старые проекты, где он не используется, испытываю адские мучения. Ну вот в ангуляре же вы наверняка используете deferred/promise, и никакого callback-hell нет и в помине? А q.all — тот же future, вид сбоку. :) Да, не так эстетично, но работает.
Типизацию можно получить в compile-time как минимум двумя способами — closure compiler и typescript.
Так можно сказать по каждому пункту. Мой посыл же в том, что:
1) выбор архитектуры и инструментов куда важнее выбора языка,
2) переписанное всегда будет лучше изначально накостыленного, вне зависимости от выбора языка.
Ведь кто-то может подумать, что надо срочно выбрасывать написанное на node.js и переписывать все на Scala. Нет, может быть, что-то и стоит выбросить, но причиной тому всегда будет не язык, а неудачная архитектура.
Angular — это прекрасно; когда приходится дописывать старые проекты, где он не используется, испытываю адские мучения. Ну вот в ангуляре же вы наверняка используете deferred/promise, и никакого callback-hell нет и в помине? А q.all — тот же future, вид сбоку. :) Да, не так эстетично, но работает.
Типизацию можно получить в compile-time как минимум двумя способами — closure compiler и typescript.
Так можно сказать по каждому пункту. Мой посыл же в том, что:
1) выбор архитектуры и инструментов куда важнее выбора языка,
2) переписанное всегда будет лучше изначально накостыленного, вне зависимости от выбора языка.
Ведь кто-то может подумать, что надо срочно выбрасывать написанное на node.js и переписывать все на Scala. Нет, может быть, что-то и стоит выбросить, но причиной тому всегда будет не язык, а неудачная архитектура.
+2
Так да, я говорил о том, что не переписал прототип.
Однако есть мнение, что двигать по рельсам дороги стройной и милой архитектуры гораздо приятнее в том случае, если тебе не чинятся постоянные препятствия, которые вроде как обходишь, но вроде как еще одной библиотекой из сотни уже используемых, и вроде как и мило получается, однако неприятный осадок остается.
В сухом остатке меньше кода — меньше багов (не всегда, но чаще всего).
Однако есть мнение, что двигать по рельсам дороги стройной и милой архитектуры гораздо приятнее в том случае, если тебе не чинятся постоянные препятствия, которые вроде как обходишь, но вроде как еще одной библиотекой из сотни уже используемых, и вроде как и мило получается, однако неприятный осадок остается.
В сухом остатке меньше кода — меньше багов (не всегда, но чаще всего).
0
Эмоциональная статья. Но так и должно быть — Вы сами должны были найти свои грабли о пройтись по ним. JavaScript всё же возник для клиентской части с её событийной моделью поведения (оттуда и колл-беки). Писать на нём серверную часть можно, но утомительно.
А ведь могли сразу взять Питон и наслаждаться ;-)
А ведь могли сразу взять Питон и наслаждаться ;-)
-3
Дык промисы жеж github.com/kriskowal/q — вот кстати дефолтная реализация.
*** Понаписывают Js под энергетиком а потом всякая нечисть является )) ***
*** Понаписывают Js под энергетиком а потом всякая нечисть является )) ***
+11
Мне промисы помогли, наверно, потому что я начал сразу с них, избежал колбэков ;)
И да, я тоже написал свой GoogleDocs+pastebin+возможность запускать.
И да, я тоже написал свой GoogleDocs+pastebin+возможность запускать.
0
промисы, asyncawait для ноды (как простое решение) или fp/frp (как чуть более хитрое) запросто избавляют от многих проблем.
особенно fp/frp, если его правильно использовать.
особенно fp/frp, если его правильно использовать.
0
понравилось изложение, спасибо)
+3
Господа, но колбэки не компонуются! Это гребаный приговор.
Браво!
0
Node исповедует (в лице npm) концепцию маленького ядра и кучи мелких модулей.
Так-то рекомендовал бы q, например.
Да и вообще, есть еще счастье в виде node --harmony (http://kangax.github.io/compat-table/es6/).
Или еще большее счастье в виде habrahabr.ru/post/116124/
Так-то рекомендовал бы q, например.
Да и вообще, есть еще счастье в виде node --harmony (http://kangax.github.io/compat-table/es6/).
Или еще большее счастье в виде habrahabr.ru/post/116124/
0
Автор не справился со сложностью и сделал ошибки, затем переписал. Причем здесь Node.js или Scala, мог бы ведь быть ровно обратный порядок. Или любые другие языки. Проблема то в том, что видимо не была изначально продумана архитектура приложения.
+1
Если нравятся акторы, но не нравятся iteratee — пишите на эрланге и будет вам счастье.
+2
Счастья на Эрланге не будет! Проверял. Эрланг счастье толко для тех, кто любит тратить свою жизнь на изобретение велосипедов.
Ибо библиотек нету.
Увы, видимо scala -реальный выбор.
Ибо библиотек нету.
Увы, видимо scala -реальный выбор.
0
Вы неправильно понимаете, как его использовать.
Эрланг — это роутинг, парсинг и поддержание коннектов. Все остальное — если его мало, тоже на э-ге; если много — на другом языке.
Эрланг — это роутинг, парсинг и поддержание коннектов. Все остальное — если его мало, тоже на э-ге; если много — на другом языке.
+1
А каких вам лично библиотек не хватило для счастья?
0
Ерланг сильно специфичный. Причем в своих специфичных нишах далеко не лучший.
Вот говорят что ерланг хорош для веба.
Лично мне не хватило нормального http клиента, например ;))
Такого, чтобы не умирал на некоторых dns. Такого чтобы >200 коннектов поддерживал ;))
А то как-то нелепо, когда язык позиционирует себя как «многопоточный для интернета»
а over 200 http-коннекшенов- не добится.
И надо самому http клиента пилить.
Я писал на эрланге паука dirs.info/spider
и стриминг сервер к-й стримит поток jpeg'ов через webcoкeты.
В итоге парсил html на недо-парсере от mochiweb'a. Он слабый. XPath имплементированы на половину только. Пилить его и пилить.
Работы со строками нормальной сильно не хватило ;)) Списки-строки идут на юг. Никогда больше!
Когда html страничка была больше 2 мегабайт строки на списках плакали и работали часами. Приходилось со страничками как с бинарниками работать.
Огорчает когда язык позиционируется как кластеризуемый из коробки, и при этом нет zero-deployment'a из коробки.
Меня gridgain на java куда больше радовал в плане легкости работы именно из-за zero-деплоймента.
В общем, считаю что зря потерял время. Лучше бы scala какую выучил или акку.
Говорят сейчас какая-то либа появилась для zero -deploymenta на ерланге. Ну дай-то бог.
Ну про надежность эрланга не буду говорить, это отдельная тема вызывающая холивары.
Вот говорят что ерланг хорош для веба.
Лично мне не хватило нормального http клиента, например ;))
Такого, чтобы не умирал на некоторых dns. Такого чтобы >200 коннектов поддерживал ;))
А то как-то нелепо, когда язык позиционирует себя как «многопоточный для интернета»
а over 200 http-коннекшенов- не добится.
И надо самому http клиента пилить.
Я писал на эрланге паука dirs.info/spider
и стриминг сервер к-й стримит поток jpeg'ов через webcoкeты.
В итоге парсил html на недо-парсере от mochiweb'a. Он слабый. XPath имплементированы на половину только. Пилить его и пилить.
Работы со строками нормальной сильно не хватило ;)) Списки-строки идут на юг. Никогда больше!
Когда html страничка была больше 2 мегабайт строки на списках плакали и работали часами. Приходилось со страничками как с бинарниками работать.
Огорчает когда язык позиционируется как кластеризуемый из коробки, и при этом нет zero-deployment'a из коробки.
Меня gridgain на java куда больше радовал в плане легкости работы именно из-за zero-деплоймента.
В общем, считаю что зря потерял время. Лучше бы scala какую выучил или акку.
Говорят сейчас какая-то либа появилась для zero -deploymenta на ерланге. Ну дай-то бог.
Ну про надежность эрланга не буду говорить, это отдельная тема вызывающая холивары.
0
Ваша история очень похода на мою — я тоже на Erlang на работе пишу пауков уже пару лет (Одного сложного дорабатываю постоянно и штуки 4 помельче). И отчасти я с вами согласен.
* HTTP клиент lhttpc работает отлично, ни разу проблем не возникало. Использовал 500-800 параллельных потоков в штатном режиме. Особо приятный момент — возможность жёстко ограничить время на скачивание странички — не уложился в 20 секунд — отбой. Но поддержку кукисов пришлось дописать. Помимо lhttpc есть вполне годные hackney и ibrowse.
* Для парсинга HTML тоже использую mochiweb_html. Даже бенчмарк делал — работает достаточно шустро, быстрее чем парсеры на большинстве динамических языков, по потреблению памяти так вообще почти всех делает. Зачем вы использовали list — строки вместо binary не знаю, видимо по неопытности…
* Для XPath брал тот же mochiweb_xpath — тут действительно была сильно урезанная версия и пришлось некоторые вещи дописывать — их сейчас влили в апстрим, так что поддержка XPath сейчас практически полная.
Насчёт zezro-deployment — не совсем понимаю что под этим подразумевается, не могу прокомментировать.
Насчёт надёжности не понял какие могут быть вопросы.
Что я получил в замен на свои «мучения»:
* Приемлемую производительность (первоначальная версия паука на Python + gevent + mongoDB для общих данных выдавала в ~10 раз меньше запросов и хрен поймёшь в каком месте был затык)
* Возможность подпатчить код без остановки паука (зашел на сервер, сделал
* Удалённый шелл сам по себе отличная штука — можно подключиться к работающему процессу и что-то там посмотреть (включить профилирование / покопаться в памяти / изменить настройки / включить-отключить подсистему). Пользуюсь постоянно.
* Относительно легко подключать другие языки — у меня к пауку подключены интерпретаторы JS и Python.
* Выпилил лишние сущности (в Python версии шаренные данные /списки proxy, статистика, cookies etc/ складывали в MongoDB, т.к. gevent по ядрам CPU не умеет расползаться, в Erlang они хранятся прямо в памяти)
* Сам код стало проще структурировать и поддерживать, т.к. OTP к этому располагает.
С вебсокетами тоже баловался — вот этот сервис написал полностью на Erlang: http://dropmail.me/ru/ и там самые что ни на есть вебсокеты.
* HTTP клиент lhttpc работает отлично, ни разу проблем не возникало. Использовал 500-800 параллельных потоков в штатном режиме. Особо приятный момент — возможность жёстко ограничить время на скачивание странички — не уложился в 20 секунд — отбой. Но поддержку кукисов пришлось дописать. Помимо lhttpc есть вполне годные hackney и ibrowse.
* Для парсинга HTML тоже использую mochiweb_html. Даже бенчмарк делал — работает достаточно шустро, быстрее чем парсеры на большинстве динамических языков, по потреблению памяти так вообще почти всех делает. Зачем вы использовали list — строки вместо binary не знаю, видимо по неопытности…
* Для XPath брал тот же mochiweb_xpath — тут действительно была сильно урезанная версия и пришлось некоторые вещи дописывать — их сейчас влили в апстрим, так что поддержка XPath сейчас практически полная.
Насчёт zezro-deployment — не совсем понимаю что под этим подразумевается, не могу прокомментировать.
Насчёт надёжности не понял какие могут быть вопросы.
Что я получил в замен на свои «мучения»:
* Приемлемую производительность (первоначальная версия паука на Python + gevent + mongoDB для общих данных выдавала в ~10 раз меньше запросов и хрен поймёшь в каком месте был затык)
* Возможность подпатчить код без остановки паука (зашел на сервер, сделал
nano src/cookie_storage.erl; rebar compile; erl -remsh spider@localhost; l(cookie_storage).
и вот уже паук работает на подправленной версии).* Удалённый шелл сам по себе отличная штука — можно подключиться к работающему процессу и что-то там посмотреть (включить профилирование / покопаться в памяти / изменить настройки / включить-отключить подсистему). Пользуюсь постоянно.
* Относительно легко подключать другие языки — у меня к пауку подключены интерпретаторы JS и Python.
* Выпилил лишние сущности (в Python версии шаренные данные /списки proxy, статистика, cookies etc/ складывали в MongoDB, т.к. gevent по ядрам CPU не умеет расползаться, в Erlang они хранятся прямо в памяти)
* Сам код стало проще структурировать и поддерживать, т.к. OTP к этому располагает.
С вебсокетами тоже баловался — вот этот сервис написал полностью на Erlang: http://dropmail.me/ru/ и там самые что ни на есть вебсокеты.
0
зеро-деплоймент когда говоришь выполнить такой-то класс на такой-то ноде
класс (вместе с зависимостями) сам туда деплоится выполняется а и возвращается результат. и все рантайме.
Ну на эрланге видать это бим должен быть ;))
ibrowse — богат на функционал но что-то типа не больше 20 коннекшенов
у остальных функционал беднее.
Хорошо что кто-то платил вам за весь этот допил. вместо того чтобы купить на эти деньги сервак поднять на нем инстансы и гонять паук помедленнее ;))
пауков-то немерянно есть написанных
класс (вместе с зависимостями) сам туда деплоится выполняется а и возвращается результат. и все рантайме.
Ну на эрланге видать это бим должен быть ;))
ibrowse — богат на функционал но что-то типа не больше 20 коннекшенов
у остальных функционал беднее.
Хорошо что кто-то платил вам за весь этот допил. вместо того чтобы купить на эти деньги сервак поднять на нем инстансы и гонять паук помедленнее ;))
пауков-то немерянно есть написанных
0
А при чём здесь язык Питон, изображённый на картинке? :)
0
Скажите, вы остались на Mongo? Используете Slick, Reactive Mongo?
0
reactivemongo и его Future отлично подошли
0
а можно еще пару слов, что понравилось, что не понравилось в reactivemongo?
0
Хм.
Понравились неявные преобразования объектов в json и обратно с ходу, ну и неблокирующие запросы офк.
Не особо радует документация на запросах сложнее find(), часто приходится лезть в API и гугл.
Вот так выглядит простенькая агрегация с подсчетом и группировкой:
Я пока этот запрос родил — прошерстил с десяток страниц апилок и гугл тредов.
Понравились неявные преобразования объектов в json и обратно с ходу, ну и неблокирующие запросы офк.
Не особо радует документация на запросах сложнее find(), часто приходится лезть в API и гугл.
Вот так выглядит простенькая агрегация с подсчетом и группировкой:
val command =
BSONDocument(
"aggregate" -> "rooms",
"$pipeline" -> BSONArray(
BSONDocument("$match"->BSONDocument("owner._id"->userId)),
BSONDocument("$group"->BSONDocument("_id"->"$language", "count"-> BSONDocument("$sum"->1)))
)
)
val comm = Aggregate("rooms", Seq(
Match(BSONDocument("owner._id"->userId)),
GroupField("language")("count"->SumValue(1))
))
Db.db.command(comm)
Я пока этот запрос родил — прошерстил с десяток страниц апилок и гугл тредов.
0
Ну это как писать на sql для тех кто никогда не видел в глаза sql, дело просто в том, что тупо не знаешь как этим пользоваться. Вот какая-нибудь обвязка а-ля query builder помогла бы
0
Да нее. С самим монго я работаю давно и успешно, знаю что к чему.
Просто чтоб это расчехлилось из rm — нужно много стараться.
Найти нужные классы, заполнить необходимые аргументы и т.п.
У них же .command сделан как раз для таких вот сложных запросов. Подход простой — нам впадлу описывать это в std api, поэтому сделаем вот так.
Просто чтоб это расчехлилось из rm — нужно много стараться.
Найти нужные классы, заполнить необходимые аргументы и т.п.
У них же .command сделан как раз для таких вот сложных запросов. Подход простой — нам впадлу описывать это в std api, поэтому сделаем вот так.
0
Господа, но колбэки не компонуются! Это гребаный приговор.
Второй раз за неделю вижу подобное утверждения. Кто-то может объяснить почему же они не компонуются?
Написать async compose для ноди не так сложно.
0
колбэки в чистом виде не компонуются. обертки уже упомянуты как и в статье, так и обмусолены в комментах.
+2
Следуя вашей логике, функции в js тоже не компонуются в чистом виде (в js нет оператора для композиции функций). Извиняють сударь, но это смешно.
Я веду к тому, что нодовский коллбеки как раз отлично компонуются. Есть конвенция: коллбек — последний аргумент для асинхронной фунции, ошибка — первый аргумент коллбека. Написать функцию композиции при условии соблюдения конвенции легко, причем можно вариировать семантику обработки ошибок, порядок вычислений.
То что действительно неудобно, так это CPS.
Я веду к тому, что нодовский коллбеки как раз отлично компонуются. Есть конвенция: коллбек — последний аргумент для асинхронной фунции, ошибка — первый аргумент коллбека. Написать функцию композиции при условии соблюдения конвенции легко, причем можно вариировать семантику обработки ошибок, порядок вычислений.
То что действительно неудобно, так это CPS.
0
Вот некий JS псевдокод с колбэками, суть которого найдется в любом примере к node.js и mongo
Скомпонуйте результаты выполнения этих двух асинхронных запросов без лишней писанины.
В Scala я сделаю так:
И это будет вполне scalish way, поскольку for скомпилится во flatMap, а это привет монадам, интерфейс которых имплементируется в scala.concurrent.Future. Все смотрится и работает целостно, без всяких конвенций и договоренностей.
db.getData(filter, function(error, someData) {
});
db.getAnotherData(anotherFilter, function(error, anotherData) {
});
Скомпонуйте результаты выполнения этих двух асинхронных запросов без лишней писанины.
В Scala я сделаю так:
val futureResult = db.getData(filter)
val anotherFutureResult = db.getAnotherData(anotherFilter)
//Future[MyDataObj]
val completeResult = for(result <- futureResult; anotherResult <- anotherFutureResult) yield MyDataObj(result, anotherResult)
И это будет вполне scalish way, поскольку for скомпилится во flatMap, а это привет монадам, интерфейс которых имплементируется в scala.concurrent.Future. Все смотрится и работает целостно, без всяких конвенций и договоренностей.
+1
В принципе должны уже быть библиотеки, которые оборачивают такие вещи. Если нет — то очень просто написать. И тогда будет:
Q.when([
Q.nfcall(db.getData, filter),
Q.nfcall(db.getAnotherData,anotherFilter)
]).done(function(){});
0
UFO just landed and posted this here
Вот, пожалуйста:
Вы правы, стандартная либа js не имеет что то подобного к waitFor. Но то, что такого комбинатора нет в стандартной поставке, еще не значит что коллбеки не могут быть скомпонованы. Нужно всего лиш написать такой комбинатор:
Тот же async — это по сути набор специальних комбинаторов для разных сценариев использования.
var futureResult = db.getData.bind(db, filter);
var anotherFutureResult = db.getAnotherData.bind(db, anotherFilter);
waitFor(futureResult, anotherFutureResult, function(error, someData, anotherData) {
// ... do the job
});
Вы правы, стандартная либа js не имеет что то подобного к waitFor. Но то, что такого комбинатора нет в стандартной поставке, еще не значит что коллбеки не могут быть скомпонованы. Нужно всего лиш написать такой комбинатор:
function waitFor() {
var args = Array.prototype.slice.call(arguments);
var done = args[args.length - 1];
var result = new Array(args.length - 1);
var hasError = false;
var left = args.length - 1;
args.slice(-1).forEach(function(asyncFn, i) {
asyncFn(function(error) {
if (error) {
hasError = true;
return done(error);
}
result[i] = Array.prototype.slice.call(arguments, 1);
left--;
if (left === 0) {
return done.apply(null, [null].concat(result));
}
});
});
}
Тот же async — это по сути набор специальних комбинаторов для разных сценариев использования.
0
Как говорит Дуглас Крокфорд у каждого языка есть свои good and bad parts. На мой взгляд проблема JS в том что он был спроектирован за 10 дней а еще благодаря MS все ее плохие стороны вместо того что бы быть ликвидированными были досконально документированы и вошли в стандарт. А сколько потратил Одерский на Scala? Тем более что автор scala до ее создания трудился над generic в java и имел прекрасное представление о недостатках java. Соглашусь с Дугласом Крокфордом о том что, js это самый широко используемый язык в мире который большинство людей его использующих не понимают. Я люблю оба языка и нахожу что каждый хорош в своей области, но несмотря на это они одинаково хорошо подходят для решения многих схожих задач.
+2
Sign up to leave a comment.
Как я проект с JavaScript на Scala переписывал