После года использования NodeJS для разработки

Предлагаю читателям «Хабрахабра» перевод понравившейся мне статьи «After a year of using NodeJS in production» за авторством Gavin Vickery. Это продолжение его статьи «Why I’m switching from Python to Node.js», которую он написал чуть больше года назад в ответ на разочарования при использовании Python и как обоснование перехода на Node.



Год разработки с штатными инструментами командной строки, клиентские проекты и выпуск обновлений для продуктов нашей компании, в двух словах, это то, чему я научился за это время. Я бы хотел поделиться опытом, но речь пойдет не столько про Node, сколько за весь JavaScript в целом.

Легко научиться, но стать мастером невозможно


Node очень прост для освоения. Особенное если вы знакомы с JavaScript. Нагуглите несколько туториалов для начинающих, поиграйтесь с Express и вы уже в теме, не так ли? Затем вы начнете осознавать, что нужно как-то взаимодействовать с базами данных. Нет проблем, запускаете NPM… Ага, всего лишь горстка приличных SQL пакетов. Позднее вы поймете, что все существующие ORM инструменты никуда не годятся и то, что базовый драйвер — это лучший выбор. Теперь у вас проблемы c реализацией своей модели и проверкой логики. Скоро после этого, вы начнете писать более сложные запросы и просто потеряетесь в callback'ах. Естественно, вы прочитаете про 'callback hell', плюнете на это дело и начнете использовать одну из многих promise библиотек. С этих пор вы просто начнёте «промисифицировать» все штуки, которые делаете, взамен на спокойные выходные.

Всё это заставляет сказать, что как-будто экосистема Node постоянно движется. И вектор этого движения не очень хорош. Новые инструменты, которые вроде как «намного круче» старых, буду встречаться каждый день. Только представьте: всегда можно найти то, что у вас есть, но только еще и «светится». Вы будете удивлены как просто это может случиться с вами. И похоже, сообщество это только поощряет. Вы используете Grunt!? Все используют Gulp!? Подождите минутку, используйте NPM нативные скрипты!

Пакеты, которые состоят из тривиального кода не более чем на 10 строк, загружаются тысячи раз каждый день из NPM. Вы серьезно? Вам правда нужно установить всю эту вереницу зависимостей, чтобы просто проверить тип массива? И эти самые пакеты используются такими гигантами как React и Babel.

Вы никогда не станете мастером того, что движется с такой, ломающей голову, скоростью. И это ни слова не говоря о «стабильности» таких движений.

Обработка ошибок по принципу «повезло\не повезло»


Если вы пришли из другого языка, такого как Python, Ruby или PHP, то вы будете ожидать, что что-то бросит вам исключение, что-то его поймает, на худой конец функция вернет ошибку. И это нормально. Совершенно нормально… Но в Node это не так. Наоборот, вы передаете ошибки в ваши callback'и или promis'ы — всё верно, никаких бросков исключений. Но это работает ровно до тех пор, пока вы не захотите получить стек вызовов у нескольких вложенных callback'ов. Не говоря уже о том, что если вы забудете вернуть callback в случае ошибки, то скрипт продолжит выполняться и вызовет набор других ошибок, в добавок к первой. Вам придется удвоить количество отладочной информации, чтобы нормально дебажить.

Даже если вы начнете «серьезно» по стандарту обрабатывать свои собственные ошибки, вы не можете (без чтения исходников) убедиться, что большая часть пакетов, установленных из NPM, используют тот же подход.

Эти проблемы приведут вас к использованию «catchall» обработчиков исключений. Которые смогут залогировать проблемное место и позволят вашему приложению не просто грациозно «упасть». Запомните, Node однопоточный. Если что-то заблокирует процесс, всё вокруг порушится к чертям. Но это круто, вы же используете Forever, Upstart and Monit, верно?

Callback, Promise или Generator!?


Чтобы управлять 'callback hell', ошибками и трудночитаемой логикой всё больше и больше разработчиков начинают использовать Promis'ы. Это способ писать код, который выглядит более-менее синхронно, без сумасшедшей 'callback' логики. К сожалению, не существует ни одного «стандарта» (как и для ничего другого в JavaScript'е) для реализации или использования Promis'ов.

Самая часто упоминаемая библиотека сейчас — это Bluebird. Она довольно хороша, быстро работает и заставляет вещи «просто работать». Как бы там ни было, я нашел очень полезным оборачивать всё, что мне нужно в Promise.promisifyAll().

По большей части я использовал замечательную библиотеку async, чтобы держать свои callback'и под контролем. С ней всё выглядело более естественно.

Ближе к концу моего опыта с Node генераторы стали более популярны. Я так и не закончил свое «погружение» в них и поэтому не могу толком ничего сказать. Хотелось бы услышать кого-нибудь, кто с ними знаком поближе.

Плохая стандартизация


Последней каплей было то, что я обнаружил отсутствие стандартов. Такое ощущение, как будто каждый имеет свое собственное представление о том, как работать с вещами, описанными выше. Callback'и? Promis'ы? Обработка ошибок? Build скрипты? Да этому нет конца.

Это всё накаляет… Никто не может сказать, как написать стандартизированный JavaScript-код. Просто забейте в гугле «JavaScript Coding Standards» и вы поймете, что я имею ввиду.

Я понимаю, что много языков не имеют строгой структуры, но они обычно имеют стандартный гайдлайн, созданный мейнтейнерами языка.

Единственное, что хоть как-то приемлемо, написали в Mozilla.

Итоги по Node


Я потратил год, пытаясь заставить JavaScript и более специфичный Node работать на нашу команду. К сожалению, за это время мы потратили больше часов на поиск документации, знакомство со «стандартами», споры о библиотеках и отладку тривиального кода, чем на что-то полезное.

Посоветовал бы я Node для больших проектов? Абсолютно нет. Будут ли люди использовать его всё равно? Конечно будут. Я тоже пытался.

Как бы там ни было, я бы рекомендовал JavaScript для фронтенд разработчиков, таких как Angular или React (как будто у вас есть другой выбор).

Так же бы я посоветовал Node для простых back-end серверов, используемых в основном для вебсокетов или предоставления API. Это можно просто сделать с Express, говорю так, потому что мы так и сделали для своего Quoterobot PDF-процессинг сервера. Это один файл, содержащий 186 строк кода, включая пробелы и комментарии. И он так же хорошо работает, насколько он прост.

Возвращение на Python


Вполне возможно вы удивлены, что я делаю сейчас? Сейчас я продолжаю писать главные части наших продуктов и API, используя Python. В основном на Flask или Django, используя либо Postgres либо MongoDb.

Это проверенный временем вариант с великолепными стандартами, библиотеками, легкой отладкой и стабильной работой. Конечно, и у него есть недочеты. Но он хорош, стоит только начать писать на нем. По некоторой причине Node привлек внимание моих глаз и затянул меня. Я не сожалею о своей попытке подружиться с ним, но чувствую, что потратил на него больше времени, чем должен был.

Я надеюсь, JavaScript и Node улучшат в будущем. Я буду счастлив попробовать его вновь.

Расскажите о своем опыте? Были ли у вас проблемы, которые я испытывал? Закончили ли вы «перескакивать» назад, на более комфортный язык?
Метки:
Поделиться публикацией
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 178
  • +9

    Есть опыт среднего проекта на node.js в связке с безумной базой Marklogic (NoSQL + RDF/triples). В том числе этот сервер на ноде умеет конвертировать модели в SPARQL-запросы и обратно, т.е. логики там достаточно.
    В общем, впечатление довольно положительное, единственно что смутило (и в чем в статье ни слова), это то что можно отстрелить себе ногу и не заметить этого. Например первый месяц у нас не работали транзакции, из-за пары строчек. При этом мы не знали об этом. Т.е. всё работало, но вот совсем не так как мы ожидали. Полез проверять: "ой, а вы в курсе что у нас все запрсоы к бд без транзакций?"
    Это пугает.
    Шутка про node.JS: "Вы начинаете асинхронно стрелять из асинхронных рук в асинхронные ноги, асинхронно не попадаете и запутываетесь в этой каше." довольно точная — если вы начинаете без четкой системы или представления как все сделать, то "вы начинаете", js позволяет начать, а дальше вы запутываетесь. Это плата за гибкость.

    • +2

      Вопрос про транзакции. Причина, по которой у вас случилась такая ошибка была в JS? В NodeJS? Или всё-таки дело в устройстве библиотеки, её API или чего-нибудь в таком духе?

      • 0

        Дело было в нашей невнимательности и всепрощении js, библиотека тут только при том, что пришлось писать хелпер для транзакций, который и не работал (точнее — открывал/закрывал транзакцию, а запросы к базе делал без указания её ID).
        В js всё может работать даже при серьезном системном баге, вместо того чтобы свалиться, и это типа плохо. Соответственно, требования к пониманию, что именно ты делаешь, возрастают.

    • –6
      Чувак, походу, во всем фиксируется на негативных сторонах. Удивительно, что перешел обратно на Python вместо Go/Rust/Ruby/Erlang.
      • +16
        Удивительно, что перешел обратно на Python вместо Go/Rust/Ruby/Erlang.

        У человека есть опыт с Python, зачем ему выбирать из Go/Rust/Ruby/Erlang? Мода типо?
        • 0
          Руби хорош, правда под него задачи 1 в 1 с питоном (только реализация отличается). И если знаешь питон, переходить на руби смысла нет.
          • –2
            Типо да, а что, незаметно? Вы видели его претензии к Python? Чувак просто ищет серебряную пулю. Удачи.
            • +3
              Мода типо?

              Ну как бы в предыдущей статье он так и пишет, «мода типо»
              I wanted something modern and designed for the new web. PHP, Python and Ruby are definitely not it
            • +17
              Python вместо Go/Rust/Ruby/Erlang.

              Смешались в кучу люди, кони…
            • 0

              Гы-гы, в другой вкладке аналогичные доводы против JS, но в пользу ClojureScript — тынц

              • +3

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


                По моему мнению, в первую очередь ноду нужно выбирать из-за асинхронности, и того, что это дает, а потом уже остальное. Но люди почему-то выбирают из-за моды, пилят достаточно большие проекты, типа другие же делают, а потом ноют.

                • +4
                  Асинхронная работа доступна сейчас практически на любых платформах, будь то php\phython\java\langname, достаточно затянуть в проект очередной reactphp\akka. То есть с этой точки зрения js\node ничего исключительного на данный момент времени предложить не смогут.

                  С другой стороны js\node могут привлекать существенно лучшим дизайном языка в мелочах, чем у того же php: те же map\reduce, методы строк и массивов существенно упрощают жизнь по сравнению с развесистыми циклами и преобразованиями на php.
                  • +1
                    не поверите, но в пхп тоже есть меп и редьюс
                    • +3
                      Им весьма непросто пользоваться по нескольким причинам, первая из которых — отсутствие стрелочных функций (js или java, подойдет любой вариант), вторая — невозможность аккуратно выстраивать цепочки для обработки потока данных.

                      Наверняка имеются соответствующие библиотеки\инструменты, но все же это не так удобно, по сравнению со стандартными средствами языка.
                      • 0
                        до недавно в js тоже небыло стрелочных функций)
                        вот первое что нагуглилось: https://github.com/Anahkiasen/underscore-php
                        • +4

                          Я пробовал пользоваться этим. И не только этим. Отчаявшись даже решил написать что-то свое. Ибо после lodash.js мне сильно не хватало возможностей. В итоге забил и снова стал писать foreach-и, for-ы и пр. конструкции для большинства задач, т.к. в PHP не только стрелочных функций нет, не только массивы не имеют объектного синтаксиса, но ещё и использование анонимных функций очень переусложнено (необходимость прокидывать всё используемое через use убивает всякое желание их использовать). Всё таки для работы в около функциональном стиле в языке должны быть для этого удобства.


                          Честно говоря после ES6-7 я не могу писать на PHP без боли. А глядя на PHP7 и его новшества я понимаю, что эти два, чем то похожих языка, пошли разными дорогами. В PHP, как мне показалось, основной курс идёт на статичную типизацию и всевозможные плюшки из Java-подобных языков. А JavaScript усиленно скачет в функциональную область. Не удивлюсь, если в каком-нибудь ES2017 нас будут ждать нативные производительные immutable-конструкции.

                          • 0

                            Если не нужно прокидывать переменные, то можно использовать костыльные стрелочные функции (см. например YaLinqo), получается компромисс между краткостью и вменяемостью кода. Если нужны use — только боль и полный синтаксис.


                            массивы не имеют объектного синтаксиса

                            Что вы имеете в виду?

                            • 0

                              Посмотрел YaLinqo… Ну это уже совсем лихо. Интерпретатор в интерпретаторе. По поводу массива: вместо $array->map array_map($array,.

                              • 0

                                Да нет там никакого интерпретатора, там вызов create_function после лёгкого преобразования строки. Впрочем, есть порт LINQ и с подключением интерпретатора для поддержки генерации запросов к БД (правда только в виде демки для MySQL, автор сдулся).


                                С функциями array_map и иже традиционная проблема PHP — у каждой функции свой порядок аргументов. Если вкладывать больше двух уровней, то получается невменяемая каша, да и сами функции — каша.

                                • 0
                                  Да нет там никакого интерпретатора

                                  Ну дык просто используется родной. Поверх уже запущенного кода. Подход, конечно, весьма производительный :)


                                  традиционная проблема PHP — у каждой функции свой порядок аргументов

                                  Да даже если привести их к одному виду, без какого-нибудь |> из функциональных языков дело с мёртвой точки тут не сдвинется.

                                  • 0
                                    Ну дык просто используется родной.

                                    Есть аналогичная библиотека, где используется неродной, строится синтаксическое дерево, всё такое. Так что почётное звание "интерпретатор в интерпретаторе" скорее заслуживает она. :)


                                    Подход, конечно, весьма производительный :)

                                    Если бы PHP не был рождён умирать, было бы лучше. :) Кэш, всё такое. Если процесс каждый раз помирает — да, не очень приятно. Но я убеждён, что использовать PHP для проектов, где надо считать миллисекунды и экономить на удобствах — не самый рациональный подход, поэтому для меня некоторое просаживание скорости не проблема по определению.

                                    • 0

                                      Боюсь, что при малом N (где N размер коллекции), разница в производительности может достигать нескольких порядков. Впрочем, в одном вы правы, в том же JavaScript-е обычно забивают на динамическое создание функций в не высоко-нагруженных местах.

                    • 0

                      Мне кажется любой язык не может предложить чего-то исключительного, везде есть плюсы/минусы и подходящие/неподходящие области применения.


                      Например, есть задача с кучей операций ввода-вывода, допустим сложная бизнес-логика завязанная на десятках таблиц, и каждую таблицу нужно чуть ли не по хаотичным правилам читать/писать в зависимости от запросов. Стандартная история вроде. И я бы не стал в данном случае выбирать ноду, если нет каких-то еще более специфичных требований, например, по производительности. Но подобную логику чаще всего больно писать в асинхронном стиле и очень больно поддерживать.


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


                      Я скорее это имел ввиду: автор выбирал инструмент, не потому что он подходил для решения задачи, а потому что так захотелось. Иначе он бы был готов ко всем проблемам.

                  • +4
                    Питон щас на 4 месте по популярности в TIOBE Index.

                    И да лапша из каллбеков размывает код, и в итоге код с колббеками сложно поддерживать, как и в случае заглушек, так и в случае установки брейкпойнтов, Код становится ассинхронным но к сожалению не организованным.

                    Gavin Vickery понял что лучше будет оверхед с абстракцией, нежели супер мощное сложно поддерживаемое приложение.
                    Другой вопрос подходит ли принцип MVC Для Ноды и Express.js ?? может потом появится другая методология которая будет включать в себя такое понятие как асинхронность!
                    • +4
                      На втором месте в этом индексе чистый C, на восьмом — бейсик, а на девятом — набирающий популярность Perl.
                      Стоит ли верить такому рейтингу, который никак не связан с рынком?
                    • +1
                      Я пришел из мира мобильной разработки. Особенно пользовался MVC паттерном. Благодря знаниям js, попытался написать сервер на nodejs и mongodb.

                      Ну что, первые дни были просто превосходны. Почему? Потому, что все было просто. Берешь request, получаешь json object, сохраняешь в базу и возращаешь ок. Потом, ежедневно API допиливался и простой API перестал быть простым. Очень большое количество кода. Из-за отсутсвия нормального IDE, приходилось писать JSdoc на каждую строку
                      /**
                      * @type {ProductModel}
                      */
                      let product = getProduct(req)


                      Начал искать Javascript со строгой типизацией. Typescript, FlowType и многие другие. Но проблема была в том, что библиотеки, которым Я пользовался, писались на vanilla-js. Приходилось открывать браузер и читать документацию. Это быстро надоедает.

                      Потом наткнулся на Spark Java (http://sparkjava.com). Особенно порадовали две вещи:
                      1. Каждый запрос это новый Thread.
                      2. Запросы на MongoDB синхронные.

                      Ну естественно, мой любимый Java.

                      Поэтому, от себя добавлю: писать проекты на JS хорошо до тех пор, пока вы помните структуру проекта.
                      • +3
                        Писать солюшены, документацию и комментарии в коде — все это необходимо делать вне зависимости от языка программирования. Иначе любой сложный проект без этого, будет запутанный.

                        Думаю любой сложный проект надо начинать делать на том инструменте, которым хорошо владеешь ты или команда. Делать что-то большое и сложное на новом, для себя языке, провально. Будет много ошибок и боли.
                        • +1
                          В данном случае, JSDoc писался только для того, чтобы редактор понимал тип объекта, ну и естественно получить autocomplete и подсказки.
                        • +2
                          1. Запросы на MongoDB синхронные.


                          Это "заслуга" не спарка, а драйверов монги. Они для java есть в 2-х вариантах: блокирующий и неблокирующий. Но для js тоже есть блокирующий драйвер.


                          Ну и странные слова про структуру проекта. Ведь тот же спарк ничем не поможет в этом (он сам по себе маленький фреймворк, который не заставляет использовать какую-то жёсткую структуру проекта, и без встроенных инструментов для IoC).


                          Так что если были проблемы в JS, то смена языка/фреймворка далеко не всегда будут панацеей.

                        • +9
                          Не так страшен черт как его малюют.

                          В начале достаточно определить Code Style в команде. Это не проблема перед началом договориться как писать код.

                          Что касается Promise, возможно автор не до конца понял суть их использования. Да, они ломают синхронную логику, к которой привыкли backend девелоперы. Но если грамотно подойти, то промисы отлично работают и код красиво структурируется цепочками вызовов.

                          Что касается исключений, то опять таки, в промисах вы смело можете их кидать и ниже по цепочке перехватывать. Это действительно удобно.

                          Что касается NPM, тут согласен — без фанатизма. Стоит брать только то, что действительно необходимо. Сам против того, что бы на каждый чих тянуть что-то из NPM.

                          Кстати, до этого писал на python (django, flask, tornado). Сейчас уже 2 года пишу исключительно на NodeJS. Пока обратно не тянет.
                          • +8

                            К хорошему быстро привыкаешь и от него больно отвыкать. Вы правда считаете, что такой код:


                            Promise.resolve()
                            .then( () => {
                                console.time( 'time' )
                                return greeter.say( 'Hello' , user )
                            } )
                            .then( () => {
                                return greeter.say( 'Bye' , user )
                            } )
                            .then( () => {
                                console.timeEnd( 'time' )
                            } )
                            .catch( error => {
                                console.error( error )
                                process.exit( 1 )
                            } )

                            И такие исчерпывающие стекстрейсы:


                            TypeError: Cannot read property 'name' of null
                                at getConfig.then.config (./user.js:19:22)

                            Удобнее, чем такой код:


                            Future.task( () => {
                                    console.time( 'time' )
                                    greeter.say( 'Hello' , user )
                                    greeter.say( 'Bye' , user )
                                    console.timeEnd( 'time' )
                            } ).detach()

                            И такие стектрейсы:


                            TypeError: Cannot read property 'name' of null
                                at Object.module.exports.getName (./user.js:14:23)
                                at Object.module.exports.say (./greeter.js:2:41)
                                at Future.task.error (./index.js:11:17)
                                at ./node_modules/fibers/future.js:467:21

                            ?

                            • 0
                              А что если в версии с промисами вывести лог таким образом:
                                  console.error( error.stack )
                              

                              ?
                              p.s. С нодой не знаком
                              • 0

                                Ничего не изменится.

                              • +2
                                С использованием генераторов(либо будущего async/await) можно писать код в синхронном стиле. Обычно использую что-то в таком духе:

                                _asyncCatch(function*(){
                                     try{
                                        var a1=yield promise1();
                                        var a2=yield promise2();
                                        var a3=yield promise3();
                                     } 
                                     catch(ex){
                                       console.log(ex);
                                     }
                                }
                                


                                У Promise должен быть описан reject.
                                • +1
                                  co( function*() {
                                      console.time( 'time' )
                                      yield greeter.say( 'Hello' , user )
                                      yield greeter.say( 'Bye' , user )
                                      console.timeEnd( 'time')
                                  } ).catch( error => {
                                      console.error( error )
                                      process.exit( 1 )
                                  } )

                                  ypeError: Cannot read property 'name' of null
                                      at Object.<anonymous> (./user.js:18:33)
                                      at next (native)
                                      at onFulfilled (./node_modules/co/index.js:65:19)

                                  Остальные варианты тут: https://github.com/nin-jin/async-js

                                  • 0
                                    Вот выдернул кусочек кода

                                            return validator
                                                .validate()
                                                .then(value => Model.findById(data.get('id')))
                                                .then(model => {
                                                    model.password = hash(data.get('password'), settings.salt);
                                    
                                                    return model.save();
                                                });
                                    


                                    Я бы не сказал, что код нечитабельный.
                                    • 0

                                      Для сравнения:


                                      validator.validate()
                                      var model = Model.findById( data.get( 'id' ) )
                                      model.password = hash( data.get( 'password' ) , settings.salt )
                                      return model.save()

                                      А теперь добавим банальный if:


                                      validator.validate()
                                      if( data.get( 'id' ) ) {
                                          var model = Model.findById( data.get( 'id' ) )
                                          model.password = hash( data.get( 'password' ) , settings.salt )
                                      } else {
                                          var model = Model.create({ password : hash( generatePassword() , settings.salt ) })
                                      }
                                      return model.save()

                                      Как вы это реализуете на промисах?

                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • НЛО прилетело и опубликовало эту надпись здесь
                                          • 0
                                            > до логического уровня «что мы делаем» с уровня «как мы это делаем».

                                            А у вас есть чему поучиться, спасибо за отличную метрику качества кода.
                                          • +2

                                            Гхм. vintage намекнул, что подход основанный на Promise, Q и пр. будет всё более и более уродливым, с каждым вветвлением. И привёл максимально простой пример на основе выше указанного. А вы зачем-то привели пример того, как можно всё архитектурно переделать, дабы избежать вветвления. А смысл? Пример не самый удачный? Ну и ладно, суть то была как раз в том, чтобы продемонстрировать что Promise-ы не решают проблему читаемости асинхронного кода, а всего лишь её смягчают. А не в том, что всякую задачу можно реорганизовать, в особенности если она простая как 2 пальца.


                                            Это как в споре о том, что Ока не самый лучший автомобиль для перевозки кирпичей, рассуждать о том, что всё не так плохо и можно прицепить к Оке тележку, а кирпичи грузить туда, а лучше купить две Оки и т.п. :)

                                            • 0
                                              Вообще в объектной парадигме большое количество ветвлений — частый признак не слишком хорошей декомпозиции задачи и предполагается, что таких мест с обилием ветвлений и тем более асинхронщиной — должно быть исчезающе мало. Вариант с рефакторингом кажется в этом смысле вполне логичным.
                                              • 0

                                                Угу, тут всё упирается вот в это: "большое количество ветвлений". Это сколько? Скажем в Promise хватает уже одного уровня, чтобы испоганить всю читаемость вхлам. Довольно грустно. Потому и ждём нативных await, извращаясь с co(* gen).


                                                и тем более асинхронщиной

                                                В nodeJS коде, в моём по крайней мере, НЕ асинхронного кода очень мало. Сама платформа располагает к асинхронности в практически любых задачах

                                                • 0
                                                  Одно простое ветвление можно аккуратно поместить в тернарник, а все что сложнее — наверное заслуживает располагаться в именованом методе\функции, что позволит так же отдельно тестировать этот участок кода и иметь в нем синхронный вход.

                                                  Попробовал представить случай — где потребовались бы размещать относительно сложный код в анонимных фунциях внутри promise — и не смог, при нормальной декомпозиции системы это кажется редким случаем.
                                                  • 0

                                                    Эдак, вы скоро и до декларативного программирования дойдёте ;)

                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                              • +1
                                                код с if вобщем-то с кучей багов, апример var model

                                                Вам показалось.


                                                Без тестов вообще ничего не получится.

                                                При чём тут вообще тесты?


                                                Дальше будет просто:

                                                storePasswordForExistingUserOrCreateNewUserWithDefaultPassword( userId, userPassword ){
                                                   if( userId ){
                                                        return db.updateUserPassword( userId, passwordEncoder.hashPassword( userPassword ))
                                                   } else {
                                                       return db.createNewUser( passwordEncoder.generateDefaultHashedPassword() )
                                                    }
                                                }

                                                Идём дальше. Что вы будете делать, когда passwordEncoder тоже потребуется сделать асинхронным? (Многие криптографические функции, внезапно, асинхронные.)

                                                • 0
                                                  Можно сделать .then внутри метода и вернуть promise, с точки зрения читабельности кода это ничего не испортит. Очевидно, что никакая декомпозиция полностью не спасет от callback\promise в асинхронном коде, но по крайней мере при должном уровне декомпозиции — они не доставят проблем.
                                                  • +1

                                                    Если это не испортит читабельность, то почему вам лень привести пример такого кода? ;-)

                                                  • 0
                                                    return passwordEncoder
                                                        .hashPassword( userPassword )
                                                        .then(hash => db.updateUserPassword( userId, hash ))

                                                    К тому же, hashPassword вероятнее всего будет внутри updateUserPassword. Так же как и в createNewUser.

                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                      • +1

                                                        Я не спрашивал "Зачем нужны тесты?". Я спросил "Какое отношение имеют тесты к обсуждаемому вопросу?"

                                                        • НЛО прилетело и опубликовало эту надпись здесь
                                                          • +2

                                                            Это не предмет обсуждения, но раз тема тестов для вас интересней, то давайте затронем и её :-) очень часто разработчики пишут модульные тесты и на этом тестирование и заканчивается. Но куда более важные тесты — приёмочные. А для них не надо как-то по особому проектировать приложение. Если вы пишете переиспользуемый код (например, библиотеку), то приёмочный тест для этой библиотеки будет одновременно и модульным. Если же вы пишете не переиспользуемый код (например, обработчик конкретного запроса пользователя), то от модульного теста тут мало пользы, ведь тут важнее не то, что он правильно работает в изолированном окружении, а то, что он правильно работает в именно вашем окружении.


                                                            В целом я склоняюсь к тому, что хороший код — это наиболее простой и понятный код. И вместо того, чтобы его усложнять, чтобы его легче было тестировать, лучше подумать как улучшить тестовый фреймворк, чтобы для тестирования не приходилось усложнять код.


                                                            Это не отменяет необходимость грамотного проектирования. Но не модульное тестирование должно быть во главе угла при проектирования всё же.

                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                              • 0

                                                                image

                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                  • 0
                                                    Давай попробую переписать для if

                                                    return validator
                                                        .validate()
                                                        .then(() => {
                                                            return Model.findById(data.get('id'))
                                                                .then(model => {
                                                                    if (model) {
                                                                        return model;
                                                                    } else {
                                                                        throw new AppError({
                                                                            status: 404,
                                                                            message: gettext('User not found')
                                                                        });
                                                                    }
                                                                });
                                                        })
                                                        .then(model => {
                                                            model.password = hash(data.get('password'), settings.salt);
                                                    
                                                            return model.save();
                                                        });
                                                    


                                                    Как по мне, не так уж и страшно. Но обычно поиск я выношу с саму модель, и проверка на найдено / не найдено уже скрыта. Поэтому в первоначальном варианте я привел без проверки на найденную модель.
                                                    • +1
                                                      1. Кода получилось в 2 раза больше (и не менее чем в 2 раза больше вероятность допустить ошибку).
                                                      2. Лесенка с 1 уровня разрослась до 6 (а мёржить такие вереницы — одно удовольствие).
                                                      3. Вам потребовалось 3 дополнительных замыкания (они не бесплатны).
                                                      4. У вас реализована совершенно друга логика (исходно проверялось передан ли id и, если нет, то модель создавалась, а не искалась).
                                                      • 0
                                                        По поводу кода, я всего лишь хотел показать, что не так страшны промисы, и с ними можно красиво работать.

                                                        Что касаемо кода — то это просто пример, как можно оформить код промисами. И код не превращен в жуткую лапшу.
                                                        • +1

                                                          Боюсь даже представить, что для вас "жуткая лапша", если этот код демонстрирует "красивую работу". :-) Вот объясните мне, зачем усложнять себе и другим жизнь, если можно этого не делать?

                                                          • 0
                                                            Судя по нашей дискуссии, читаемость / не читаемость цепочек — индивидуально.

                                                            Если честно, даже аргументировать мне вам нечем. :-) Я просто вижу цепочку и понимаю что происходит. Так же и программеры в моей команде свободно читают и понимают цепочки.
                                                            • +1

                                                              Это мне напоминает слова адептов Пунто Свичера: "Зачем мне ваш десятипальцевый слепой метод? Я и двумя пальцами огого как быстро набираю текст!".

                                                              • 0
                                                                Если человек не может мыслить и представить код в асинхронном стиле, а только в линейном. То это проблема не языка, а человека.

                                                                Ну не может он. Тут только одно — выбрать другой язык.

                                                                Мы проблем с читаемостью и пониманием кода не имеем. Ваши доводы, что код нечитаем — поверьте, всего лишь только ваши личные доводы.

                                                                В принципе не ради ходивара все затевалось. Я только хотел показать в начале, что цепочки не так уж и страшны. А юзать их или что другое — выбор либо человека, либо команды.
                                                                • +1

                                                                  Не надо юлить ;) Код на fiber-ах и async-ах объективно проще и понятнее. Так же как и синхронный код куда проще и понятнее, нежели всё остальное. Тут личные доводы вовсе не причём :) Речь же идёт не о табах и пробелах.

                                                                  • 0
                                                                    Голословное заявление.

                                                                    Мне код на промисах понятен. Команде код понятен. Скажите, что нам сделать, что бы понять вашу точку зрения?
                                                                    • +1

                                                                      Ну дык есть некоторая разница между словами "понятен" и "понятнее". Сравните, скажем, код на Promise-ах с синхронной реализацией. Даже не знаю о чём тут спорить.

                                                                      • +2

                                                                        Боюсь это не излечимо :-) Знаете, вот есть такие индивидуумы (и даже команды в прошлом), которые пишут по несколько операторов в строку. И аргументация у них точно такая же: "Мне же всё понятно! Это вы, убогие, не способны быстро читать неотформатированный код!".


                                                                        Объективные факты:


                                                                        1. В 2 раза больший объём кода в принципе не может считываться также быстро. Как бы вы ни были натренированы.
                                                                        2. Использование замысловатых конструкций требует специальной дополнительной подготовки от программиста.
                                                                        3. Чтобы не напортачить, требуется особое внимание достаточно высококвалифицированных разработчиков. Типичная ошибка — не залогировать ошибку в конце цепочки.
                                                                        4. Асинхронный код сложнее в отладке. Вы получаете кривые стектрейсы. Вы не можете пройтись дебаггером по шагам. Вы не можете посмотреть значения переменных, выше по стеку, так как давно уже из него вышли.

                                                                        Уверен, вы на столько круты, что можете писать хоть лесенкой, хоть столбиком, хоть цепочечкой. Но 99% людей — не такие. Чем сложнее конструкции, тем больше они допускают ошибок. Так что код, который требует высокой квалификации — это плохой код. А настоящий профессионализм — не в том, чтобы читать и писать заклинания, а в том, чтобы писать так, чтобы в нём мог разобраться даже дилетант. А где разберётся дилетант — там профи и ошибки не допустит.

                                                                        • 0
                                                                          .
                                                                          • 0
                                                                            Еще раз повторю — если избирается подход для написания Promise, то кроме как цепочкой писать не получится. Если не нравятся промисы, есть другие инструменты и подходы.

                                                                            Повторюсь, я написал цепочку не ради холивара. Не надо доказывать мне, что квадратное круче теплого, или наоборот.

                                                                            Мир дружба жвачка :-)
                                                                            • 0
                                                                              В 2 раза больший объём кода, Асинхронный код сложнее в отладке...
                                                                              В данной ветке речь про сложность кода, и у асинхронного кода она выше, на написание кода тратиться больше времени, на отладку больше времени, выше вероятность ошибки, вместо обдумывания логики приложения вы тратите время на обдумывание как построить асинхронный код, в итоге на завершение потребуется больше времени (2 года вместо одного например) и более дорогие разработчики, а производительность может быть ещё и ниже чем у синхронного кода (сюрприз?).

                                                                              Поэтому асинхронный код не не нужно использовать везде подряд, а там где он нужен.

                                                                              Боюсь это не излечимо :-)
                                                                              Нет, осознание иногда приходит (после года, два, пять), данная статья (и другие подобные) тому подтверждение. Разработчик вам не поверит, ему нужно это пережить.
                                                          • 0

                                                            А зачем увеличивать уровень вложенности и писать then внутри другого then? Одним уровнем не обойтись?

                                                          • 0
                                                            Я еще использую небольшой хак-обертку для генерации promise(внимание, довольно своеобразное решение, также нет обработчика ошибки для случаев отличных от сигнатуры (err, result)=>{}):

                                                            Object.defineProperty(Object.prototype, 'getPromise2', {
                                                                value: function (func, args, argCount, argResolve) {
                                                                    argCount=argCount||1;
                                                                    argResolve=argResolve||0;
                                                                    var _this = this;
                                                                    var f=func===-1?_this:_this[func];
                                                                    if(!Array.isArray(args))
                                                                        args = [args];
                                                                     
                                                                    return new Promise((resolve, reject) => {
                                                                        var self=this;
                                                                        if(argCount==2){                
                                                                            f(...args, function (err, res) {
                                                                                if (err)
                                                                                    reject(err);
                                                                                    //throw(err);
                                                                                else
                                                                                    resolve(res);
                                                                            });
                                                                        }
                                                                        else{                
                                                                            f(...args, function () {
                                                                                var result=arguments[argResolve];
                                                                                resolve(result);
                                                                            });
                                                                        }
                                                                    });
                                                                }
                                                            });
                                                            
                                                            
                                                             
                                                            _asyncCatch(function*(){
                                                            var html=yield request.getPromise2('get', {
                                                                        url: url,
                                                                        encoding: 'UTF-8',
                                                                        gzip: true
                                                                    }, 3, 2, true);
                                                            });
                                                            console.log(html);
                                                            


                                                            Правда, не во всех случаях такое решение подойдет, но вообще довольно удобно.
                                                            • 0

                                                              Попробуйте fibers — это куда удобней. На худой конец — co, а не стрёмный _asyncCatch.

                                                              • 0
                                                                Свои костыли писать полезно иногда. А за совет — спасибо.
                                                                И, если не секрет — в чем стремность _asyncCatch'а заключается, кроме названия функции? Работает он приблизительно так же, как async/await из ES7:

                                                                async function testAsync() {
                                                                  try {
                                                                    let html = await request.getPromise2('get', {
                                                                            url: url,
                                                                            encoding: 'UTF-8',
                                                                            gzip: true
                                                                        }, 3, 2, true);
                                                                  } catch (err) {
                                                                    console.log(err);
                                                                  }
                                                                }
                                                                


                                                                Вот getPromise2 стремен, тут не поспоришь.
                                                                • 0

                                                                  И название стрёмное. И документацию не найти. И чёрт его знает, что там в реализации. Судя по всему это то же, что и "co", но с меньшими возможностями.

                                                                  • 0
                                                                    Это вообще самопальная функция-переделка в 14 строк из какой-то функции, спертой вообще неведомо где и приспособленная для своих нужд. Назначение — эмуляция async/await, дабы на каждый проект за собой babel или зависимости не таскать.
                                                                    То, что есть готовые модули типа того же co или async — это круто, но иногда достаточно и самопальных функций.

                                                                    var _asyncCatch=function(generatorFactory){
                                                                        var generator = generatorFactory.apply(this, arguments);
                                                                        var handleResult = function(result) {
                                                                            if(result.done) return result.value;
                                                                            if(result.value.then)
                                                                                return result.value.then(function(nextResult) {
                                                                                        return handleResult(generator.next(nextResult));
                                                                                    }, function(error) {
                                                                                        generator.throw(error);
                                                                                    }
                                                                                );
                                                                        };
                                                                        return handleResult(generator.next());
                                                                    }
                                                                    
                                                                    • 0

                                                                      Самопальная функция, возвращающая иногда промис, иногда что-то ещё, а иногда кидающая исключение. Что плохого в одной небольшой зависимости? Она всего чуть более 200 строк.

                                                                      • 0
                                                                        Самопальная функция, возвращающая иногда промис, иногда что-то ещё, а иногда кидающая исключение

                                                                        Зато сколько азарта и веселья (при дебаге)!

                                                                        • 0
                                                                          Так и есть)
                                                                          Что до возврата всего подряд — если внимательно просмотреть листинг функции, то станет понятно, что она проходится по всем елдам внутри generatorFactory, вываливая exception в случае, если в Promise сработает reject.
                                                                          Как эта хреновина работает — можно посмотреть здесь — https://davidwalsh.name/async-generators либо тут(похоже именно здесь эту функцию я и брал) — http://bhashitparikh.com/2014/06/04/better-jquery-ajax-with-es6-generators.html.
                                                                • 0
                                                                  Почему fibers предпочтительней co?
                                                                  • 0
                                                                    1. Быстрее.
                                                                    2. Не требует оборачивания всех функций в обёртку.
                                                                    3. Адекватные стектрейсы.
                                                                    • 0
                                                                      Некоторые считают , что нетребовательность волокон к оборачиванию всех функций — это не безусловный позитив.
                                                                      • 0
                                                                        Выходит, может возникнуть такая ситуация, когда будет не очевидно, что код, который вызывается глубоко внутри нескольких вложенных функций, на самом деле, выполняет что то асинхронно.
                                                                        В концепции async await или co, поведение всегда очевидно.
                                                                        • 0

                                                                          Ну а с промисами может возникнуть такая ситуация, когда будет не очевидно, что код, который вызывается глубоко внутри нескольких вложенных промисов, на самом деле, выполняет что то синхронно.


                                                                          А "некоторые" — не очень хорошие архитекторы. Проблема, описанная там, наблюдается даже в полностью синхронном коде — ничто не мешает где-то в глубине функции query вызвать колбек, который меняет глобальную переменную requestCount. Так что async-await никак не спасают от необходимости осторожно обращаться с глобальным состоянием.

                                                                          • 0
                                                                            Глобальная переменная там все таки только для примера и наглядности того, как с fiberами легко создать себе race condition. В полностью синхронном коде race condition не бывает.
                                                                            Просто fiberы это слишком очень гибкая вещь. Как я понимаю, можно изменить поведение функции, сделав ее асинхронной, при этом никак не изменяя ее вызовы, они будут также работать. Это конечно круто, но, мне кажется, все таки безопаснее, когда в самом вызове функции видно, что вызов этот асинхронный.
                                                                            В случае с генераторами, как раз придется еще вносить изменения в вызывающие функции, что конечно раздражает, но такой код становится более явным и предсказуемым, а это плюс.
                                                                            Короче, await в вызове async функции — это совсем не избыточная информация в синтаксисе, он нужен для того, чтобы прочитав код, мое представление о нем соответствовало тому, что он на самом деле делает:) А fiberы создают иллюзии ;)
                                                                            • 0

                                                                              Любой race condition — следствие неправильной работы с разделяемым ресурсом. Глобальная переменная — частный случай. Да, в синхронном коде она не будет случайной, как в параллельном. Но суть ошибки та же самая — мы прочитали значение, никак его не залочив, потом другой код, которому мы передали управление (вызов функции/обращение к свойству/запуск сигнала/yield), его изменил, а потом мы записали новое значение, затерев чужие. async/await не спасёт вас от такого рода ошибок.


                                                                              Мы проходили уже то же самое с обработкой ошибок:


                                                                              1. Сначала функции возвращали результат или ошибку.
                                                                              2. Выяснилось, что любая функция может попасть в исключительную ситуацию и должна вернуть ошибку.
                                                                              3. Весь код получался усеял копипастой вида "если функция вернула ошибку, нужно тоже вернуть ошибку. И так после вызова каждой функции.
                                                                              4. Потом додумались, что если в 99% случаев обработка ошибки заключается в том, чтобы пробросить её выше по стеку, то логично сделать это поведением по умолчанию.
                                                                              5. Пришли к соглашению, что любой код в любом месте может быть прерван исключением и нужно писать свой код имея это ввиду. А для изменения поведения по умолчанию ввели конструкцию try-catch.

                                                                              Также и с асинхронностью. 90% функций так или иначе могут привести к необходимости произвести асинхронную операцию. Это не какая-то исключительная, а вполне себе типичная операция. А специальный синтаксис имеет смысл вводить лишь для особых ситуаций. Например, когда нам надо, чтобы никто не изменил переменную без нашего ведома:


                                                                              exclusive( requestCount ) { //никто, кроме кода этого блока не может изменить переменную
                                                                                  var nextValue = requestCount + 1 // посчитали новое значение, но почему-то сразу его не записали
                                                                                  // можем вызывать что угодно и даже засыпать
                                                                                  exclusiveRequestCount = nextCount // установили новое значение
                                                                              } // освободили глобальную переменную.
                                                                        • +1
                                                                          Еще одно субъективное замечание: node-fibers — это все таки что-то из области черной магии), если сравнивать его с co (200+ срок на чистом js).
                                                                          Написан он на С, код с использованием fibers тоже выглядит шаманством) В общем, это не просто js библиотека и это настораживает.
                                                                          К тому же, fibers уже не станут мэйнстримом, так как node.js отчетливо движется в сторону async await. А наличие камьюнити в наше время решает.
                                                                          • –1

                                                                            Поэтому и надо популяризовывать правильные решения. К сожалению у JS нет толкового диктатора. А власть толпы ни до чего хорошего никогда не доводит. Чего только стоит цирк с пропертями:


                                                                            1. Была простая концепция: всё есть объекты и у объектов есть поля.
                                                                            2. Добавили Object.defineProperty и кучу свойств у каждого поля: перечеслимое, изменяемое, функция получения значения, функция установки значения.
                                                                            3. Добавили кучу мета методов в Object.prototype.
                                                                            4. Перенесли часть из них в Object.
                                                                            5. Добавили Symbols. Теперь у каждого объекта есть поля по строковым ключам и по символьным.
                                                                            6. Добавили Reflection со всем тем же самым.

                                                                            Куда движется JS? В сторону PHP? ;-)

                                                                            • 0

                                                                              Правильное решение это Dart:


                                                                              1) Все есть объекты, наследование на базе классов с миксинами, генерики
                                                                              2) Свойства с сеттерами и гетерами )) встроены в язык
                                                                              3) async/await вместо callback-hell, встроено в язык
                                                                              4) exceptions/try/catch встроено в язык
                                                                              5) Вменяемый "диктатор" отвечающий за развитие давно уже зрелого SDK разработанного в едином концептуальном стиле
                                                                              6) Менеджер пакетов (типа npm)
                                                                              7) Очень легко научиться.
                                                                              6) Можно начинать с динамической типизацией и при необходимости вводить постепенно строгую.
                                                                              7) Тесты
                                                                              8) @Метатеги
                                                                              9) Трансформеры
                                                                              ..


                                                                              И да, Google конечно обязательно забросит/закроет Dart как и множество других проектов… ага


                                                                              Допилят Flutter (спасибо Oracle с судами про Java) будет совсем весело..


                                                                              Но мыши плакали, кололись и продолжали увлеченно спорить какими костылями и как сподручнее размахивать чтобы взлетать из болота… лишь бы не выходить из зоны комфорта ))


                                                                              A JS движется в сторону WASM ;-)

                                                                              • 0

                                                                                Почему не Haxe?

                                                                                • 0

                                                                                  Haxe — нельзя отлаживать без компиляции.
                                                                                  Dart — можно делать полноценную отладку в IDE без компиляции(с возможностью посмотреть значение любой переменной на брейкпоинте просто наведя на нее мышь). В Dartium встроена Dart VM. Изменили код, нажали F5 в Dartium. Разработка быстрее и удобнее.
                                                                                  Серверный код вообще не надо компилировать, он работает в DartVM быстрее и устойчивее чем JS на Node.


                                                                                  И на Haxe не пишут Angular ))
                                                                                  Приложение на AngularDart(которое транслируется в JS) работает быстрее чем AngularJS вариант, что как бы говорит о качестве компиляции(в команде Dart люди которые Chrome разрабатывали). Которой Haxe в силу основного упора на многоплатформенность похвастаться не сможет даже в теории.

                                                                                  • 0
                                                                                    1. Компиляция происходит в любом случае. На сервере или в браузере.
                                                                                    2. Haxe тоже можно отлаживать из IDE с просмотром значений переменных, брейкпоинтами и прочим.
                                                                                    3. Возможность отладки в браузере, которым никто не пользуется — так себе фича.
                                                                                    4. Только что вы кичились трансформерами — они тоже в браузере налету применяются?
                                                                                    5. Ангуляр, что первый, что второй — редкостная порнография.
                                                                                    6. Свежо предание. http://qiita.com/laco0416/items/df2e32787b36a01c3d6d
                                                                                    7. Зато на Haxe можно нативные мобильные приложухи пилить.
                                                                                    • +1
                                                                                      1. "Компиляция происходит в любом случае. На сервере или в браузере." — Обоснуйте пожалуйста. Я утверждаю, что на сервере Dart код выполняется в Dart VM без компиляции.
                                                                                      2. В случае с компиляцией Haxe в JS, отладку можно будет делать только после компиляции(иначе как то что отлаживается будет взаимодействовать с DOM), так?
                                                                                      3. Dartium = Chrome-V8+DartVM и корректные полифилы для всех остальных браузеров в SDK присутствуют. Так что фича рабочая.
                                                                                      4. Трансформеры это про кодогенерацию. Выполняет их pub. Бывают проекты и без нее. Необходимый трансформер это например dart2js — нужен только перед выкладкой, в процессе отладки — не запускается. Или трансформер нужен, например, при работе с Polymer.
                                                                                      5. Интернет из фо порн ;-)
                                                                                      6. Предание 22 октября 2014 и что? Сейчас речь идет про Angular2
                                                                                      7. Flutter is a new project to help developers build high-performance, high-fidelity, mobile apps for iOS and Android from a single codebase.

                                                                                      Про Haxe? расскажите пожалуйста — моб. приложение будет одно и тоже для iOS and Android? Или их можно писать дергая платформозависимые API?

                                                                                      • 0
                                                                                        1. Без компиляции исполняются лишь машинные коды. Остальное либо транслируется, либо интерпретируется.
                                                                                        2. Разумеется.
                                                                                        3. Да-да, тут для JS-то не всегда полифил адекватный есть. Взять тот же WebRTC2.
                                                                                        4. То есть препроцессинг всё равно будет.
                                                                                        5. В данном случае, это — зоопедонекропорно.
                                                                                        6. Пруфлинки приветствуются.
                                                                                        7. Оно компилируется в основной язык целевой платформы с возможностью прозрачно и эффективно использовать все её возможности?
                                                                                        8. Одна кодовая база транслируется в разные языки. Можно использоваться платформозависимые API на полную катушку.
                                                                • 0
                                                                  Я иногда выношу логику в отдельные маленькие функции и тогда код будет выглядеть примерно так:
                                                                  return validator
                                                                  .validate()
                                                                  .then(findModelById)
                                                                  .then(updatePassword);
                                                          • +1
                                                            Щас понабегут проповедники и религиозные фанатики и заминусуют пост, и кучу комметов в довесок.
                                                            Да как ты посмел обидеть ноду :D
                                                            • –1
                                                              Привет КЭП :)
                                                              • –5
                                                                Простите забыл перелогинится. :D
                                                                • 0
                                                                  Да не, так нормально тоже :)

                                                                  Далее Обращаюсь НЕ к автору предыдущего комментария…

                                                                  Вообще, конечно, хотел просто ничего не писать, но это, что на пустом месте за кому-то показавшимся неудачным или неуместным юмор можно отхватить — надоело. Оно понятно, что «петросянство», но, что с Вами не так?

                                                                  God Mode On — вообще не понимаю, что Вам с того, что двое в каментах решили потроллить друг друга?

                                                                  Вообще, я люблю JS, но я одинаково не понимаю И Хейтеров И Обожателей. И если Вы подумаете хоть немного, то поймёте, что «Привет КЭП» — относится и к тем и к другим. Впрочем как и исходный комментарий про «сейчас набегут». Оба враждующих лагеря могут поразжигать на этой теме :)

                                                                  Т.е., я не хожу и не рассказываю всем как я Люблю или Не Люблю ноду, JS и всё, что с этим связано. Коллеги, ни в любви ни в ненависти к JS нет ничего прикольного!

                                                                  ИМХО — пытаться понять JS через парадигмы других ЯП — гиблое дело. Из комментария ниже про 300 мегабайт node_modules — в этом нет ничего плохого. Ничего хорошего тоже нет, но и плохого нет. Это просто так, как есть.

                                                                  Считайте, что это такой вот DZEN.
                                                                  • +3
                                                                    Из комментария ниже про 300 мегабайт node_modules — в этом нет ничего плохого. Ничего хорошего тоже нет, но и плохого нет. Это просто так, как есть.

                                                                    Когда CI на каждый коммит вытаскивает репозиторий и потом накатывает вендоринг, это очень долго и очень много трафика утекает.
                                                                    На каждый коммит по 300Мб с инета тянуть это плохо.
                                                                    • +1
                                                                      А как насчёт кеширования node_modules например? Не путь самурая? Если флоу дорос до использования CI то и подходы кеширования использовать не грех. Достала CI тот же package.json, сравнила версии либ, если ничего нового, используем то что в кеше. Да и на каждый commit нет повода её дёргать. Скорее на каждый pull request. Это не так часто как могло бы показаться.
                                                            • –3

                                                              Ну не так страшна nod'a, проблема в том что js надо знать не плохо и как минимум npm пользоваться "каждый день". Вот к примеру автор совсем не знает про knex. И еще десятка 2 полезных пакетов для сервер сайда. Тут трабла в их поиске и адекватной оценке.

                                                              • +1

                                                                Мне интересно, за что минусуют человека? У кого-то плохой опыт был с этой штукой?

                                                                • 0

                                                                  Ну это же топик про гнев и какая нода плохая, опять же knex не orm но всем видно насрать :)

                                                              • +5
                                                                Добавлю своей боли. У нас npm используется для разработки и сборки фронта. Так вот фронт написан на ReactJS. Собирается все с помощью gulp и вот в чем боль. Зависимости для работы всего этого (каталог node_modules) занимают 120Мб в проекте. Это с третим npm. Со вторым вообще 800Мб. Извините но это Адъ. 800Мб Карл, просто чтобы собрать фронтэнд. Так для справки кодовая база (js, php) без вендоринга весит 22Мб. Вендор php (42 Мб) и папка с пакетами ноды 120Мб. Wft? Причем там ничего не используется в продакшене из этого каталога. Вообще ни чего. (babel, gulp, react, webpack — вот эти 4 штуки вытягивают 100Мб зависимостей)
                                                                • +1
                                                                  Попробуйте устанавливать с флагом production. npm install --production. Просто по умолчанию установки пакетов тянутся зависимости нужные только при разработке этих пакетов, вроде eslint и прочих, но без которых можно обойтись, если использовать просто как пакеты.
                                                                  • –1

                                                                    Так а в чем боль? Вам место жалко на диске или вы храните node_modules в репозитории.

                                                                    • +2
                                                                      Я с помощью CI запускаю сборку и тесты на каждый коммит. И каждый раз заново пулю репозиторий и заново все накатываю, чтобы никакие кеши не дали сайд эффектов. Да мне жалко на каждый коммит тащить с инета половину интернета. Конечно в случае разработки без CI и без автоматизированного тестирования проекта все супер. Но х х и в продакшен не наш путь. Каждый раз приходится ждать по 2-5 минут пока нода соизволит выкачать пол мира, а хочется быстрой обратной связи.
                                                                      • –1
                                                                        Вы что-то делаете не так. У меня тоже тесты на каждый коммит, но node_modules закеширован и обновляется только если изменится packages.json и/или npm-shrinkwrap.json.
                                                                        • 0
                                                                          Поясняю:
                                                                          1) Каждый раз при коммите CI делает git clone (в отдельный каталог)
                                                                          2) Далее переходит в каталог с кодом и устанавливает зависимости
                                                                          3) После этого производит сборку пректа
                                                                          4) После этого запускает тесты
                                                                          5) После этого анализирует результаты тестирования

                                                                          Теперь вопрос, что я делаю не так?
                                                                          • 0

                                                                            Угу. Учитывая что node_modules создаёт такие проблемы при таком подходе, а от npm вы отказываться не собираетесь, ну так откажитесь от этой схемы в пользу другой. Как-минимум п.2 можно усложнить и если bower.json, package.json и пр. не менялись с прошлого раза, то и не грузить ничего заново. У нас пока подгрузка зависимостей занимает 8-10 минут. И это не выносимо долго. Но прибегаем к такой подгрузке только если зависимости были изменены.

                                                                            • 0
                                                                              Не совсем понятно зачем п.2 если node_modules можно положить просто на уровень выше, чем каталог куда делается git clone.
                                                                              • 0
                                                                                http://12factor.net/ru/dependencies — приятного чтения
                                                                                • +2

                                                                                  1.5) ln -s ../node_modules node_modules (не говоря про то, что npm может пару вариантов для решения еще предложить, типа линковки пакетов, выбора источника и так далее)
                                                                                  2) npm install


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

                                                                                  • +1

                                                                                    Docker позволяет легко и просто "ставить систему с нуля". Правда с node_modules — та же беда, но её легко обойти:


                                                                                    1. Обновляем репозиторий на хостовой системе.
                                                                                    2. Добавляем в контейнер package.json.
                                                                                    3. Выполняем в контейнере npm install.
                                                                                    4. Добавляем в контейнер остальные исходники.

                                                                                    Таким образом, если package.json не менялся, то будет взят снепшот из кеша с установленными node_modules.

                                                                                    • 0
                                                                                      Можно просто закинуть путь к node_modules в process.env.NODE_PATH
                                                                                    • 0
                                                                                      Посмотрел: так себе, не очень понял накой это читать. Речь же про тестовую среду, так почему нельзя общие node_modules держать для всех билдов и только при изменении package.json их «перестягивать»?
                                                                                      Что, разве build среда не может узнать что package.json изменился, и сходить на уровень выше, скопировать туда package.json и установить там всё через тупо npm install?
                                                                                  • 0
                                                                                    Все так, но что если зависимости устанавливать глобально?
                                                                                    Репа скачается, а зависимости будут использоваться уже ранее установленные
                                                                                    • 0

                                                                                      Так и не ставьте зависимости глобально. npm прекрасно работает с локальными зависимостями; более того, это рекомендованный подход.

                                                                                • 0

                                                                                  Вебпак позволяет за милисекунды билдить проект и на горячую подменять стили, а при опрелеленных условиях и код, и шаблоны, и все что угодно. То есть можно добиться того, что после нажатия на ctrl+s все применится до того как вы успеете взгляд на монитор с браузером перевести. А Ваши претензии сводятся к медленной обратной связи?


                                                                                  А поповоду выкачивания, чтобы не юзать версии из кеша, во избежание сайд-эффектов, это по-моему на уровне паранойи. Нет, стандарты по сборке и тестированию могут быть разными, но тогда чем обусловленно недоверие именно к системе кеширования в npm, при условии использования 120мб стороннего кода?


                                                                                  Зафиксировать версии, один раз проверить сборку после очередного коммита, при смене версий еще раз проверить, все ли подтянулось, обновилось, либо даже автоматический тест написать. Тоже не ваш путь?

                                                                                  • 0
                                                                                    Разверните у себя Sinopia и используйте ее для кэширование NPM пакетов.
                                                                              • +1
                                                                                По поводу стандартов для написания JavaScript, могу посоветовать взглянуть на Airbnb JavaScript Style Guide github.com/airbnb/javascript
                                                                                • +12
                                                                                  Да в том-то и проблема, что этих стандартов как собак нерезаных в квадрате. Airbnb, wikimedia, google, на любой вкус. Точки с запятыми, фигурные скобки и их размещение, отсутствие, наличие и опциональность этих вещей, количество пробелов (или табов), переносы строки — в любом сочетании, оптом и в розницу. ИЧСХ, все неконсистентные и все нелогичные.
                                                                                  • +2
                                                                                    Надо все это смержить, пофиксить конфилкты, стандарт готов ) *шутка*
                                                                                  • 0

                                                                                    Просто выберите, который ближе по душе и используйте. Для других языков разве везде единый стиль?

                                                                                    • 0

                                                                                      Но в этом же и прелесть. Если для человека не достаточно авторитетны стандарты от гугла, или проект входящий в топ 15 по количеству звезд на гитхабе, и он не может сделать свой выбор, или сделать свои гайдлайны с блекджеком и прочими вещами (благо инструментов валом), а предпочитает только от производителя, то это уже идеологические проблемы.

                                                                                • 0
                                                                                  Самый популярный npm пакет для http запросов с названием «request» у меня при очень большом количестве запросов вызывал утечку памяти, Карл! После длительных мучений и поисков причины утечки проблема была обнаружена именно в этом пакете. После замены «request» на аналог (вроде requestify он назывался) проблема исчезла. Причем в описании самого «requestify» тогда было написано что-то вроде: «Мы понимаем на сколько ужасен „request“ именно поэтому создали этот пакет». После этого я очень аккуратно отношусь к node вцелом и выбору npm пакетов.
                                                                                  • +1
                                                                                    Вы так говорите, будто в питоне все пакеты кошерные и пишут их академически подкованные, сертифицированные и ВСЕГДА соблюдающие пеп8(а это же стандарт!) люди. Если бы так было, никогда бы не вышел к примеру ConfigParser2. А попробуйте загуглить «python event emitter» и удивитесь сколько пакетов делают одно и то-же с разной степенью кривизны.
                                                                                    А вот взять общеизвестный пакет logger
                                                                                    https://docs.python.org/3/library/logging.html — методы там в camelCase, не совсем по стандарту, но он вроде как не запрещает, но потом ведь и ваш код становится солянкой, где одни методы вызываются так, другие почему-то иначе. А вот если взять тот-же JS так я не могу вспомнить ни одну популярную библиотеку где в последний раз видел, чтобы имена методов были не camelCase. В общем, не надо отбеливать то что белым не является, и очернять то что вовсе не черное, пакеты как и языки написаны людьми и априори не могут быть идеальными.
                                                                                    • +1
                                                                                      P.S. это был не requestify, a hyperquext.
                                                                                    • +4
                                                                                      Если вы захотите написать асинхронный неблокирующий сервер на python, к примеру на twisted или tornado, каким образом вы сможете избежать callback-ов, Deferred-oв или yield-ов?
                                                                                      В twisted нету errback-ов? Все само ловится через try/catch?
                                                                                      На node нельзя писать синхронно? Нельзя кластеризировать? А потоки вам при работе с tornado сильно упростят логику?
                                                                                      Работа с асинхронным кодом имеет один и тот же стандарт в twisted и tornado? А стандарт такой вообще есть?
                                                                                      • 0
                                                                                        каким образом вы сможете избежать callback-ов, Deferred-oв или yield-ов? Все само ловится через try/catch?
                                                                                        В питоне есть gevent.
                                                                                        На node нельзя писать синхронно?
                                                                                        Вы имеете ввиду блокирующие вызовы или файберы?
                                                                                        один и тот же стандарт в twisted и tornado?
                                                                                        Для этого есть async.io

                                                                                        А вообще «асинхронщина» нужна в 5% случаев если не меньше (по моей статистике), а питон умеет и так и эдак в отличие от ноды.
                                                                                        • +1
                                                                                          https://www.npmjs.com/package/fibers
                                                                                          http://venkateshcm.com/2014/04/Reactor-Pattern-Part-4-Write-Sequential-Non-Blocking-IO-Code-With-Fibers-In-NodeJS/ — о таких файберах речь?

                                                                                          А вообще согласен, с большинством задач и django и flask замечательно справляются и делают это на хорошем уровне. Но не со всеми и не всегда.
                                                                                          Я кстати тоже очень люблю питон, и js люблю и спорить кто из них лучше не хочу, но вечные нападки неосиляторов со статическим ООП(как будто JS отменял ООП или невозможно прибить все типы гвоздями при необходимости, но это уже другая история...) головного мозга(это я не про вас, это я про крайние случаи, которые очень часты в интернетах) в сторону JS слегка расстраивают.
                                                                                          • 0
                                                                                            асинхронный комментарий получился )
                                                                                            • +1
                                                                                              > но вечные нападки неосиляторов со статическим ООП(как будто JS отменял ООП или невозможно прибить все типы гвоздями при необходимости

                                                                                              Так JS не предоставляет почти никаких инструментов, так характерных для ооп языков. Просто пройдусь по списку:
                                                                                              1) Автоматический рефакторинг — нет или очень слабый (для этого IDE должна хорошо понимать код)
                                                                                              2) Инкапсуляция — private\protected в es6 классах можно реализовать только окольными путями
                                                                                              3) Полиморфизм — интерфейсов нет и единственное что мы можем — это намекнуть на структуру ожидаемого объекта другому программисту в jsdoc
                                                                                              4) DI\IoC — никаких constructor injection, только хардкор
                                                                                              5) Возможность не держать в голове типы всех переменных в области видимости — тоже ожидаемо нет
                                                                                              6) Grasp паттерны:
                                                                                              * отделение асинхронного кода от синхронного (контроллер) — сложно и часто не имеет смысла, потому что асинхронно все
                                                                                              * слабое зацепление — сложно, потому что в большинстве случаев слишком многие подробности объекта доступны извне
                                                                                              * устойчивый к изменениям — нет, потому что у нас отсутствует интерфейс, где мы можем задекларировать api

                                                                                              Вот и получается, что ооп как-бы есть, но одновременно его как-бы нет.
                                                                                              • 0
                                                                                                Я не сомневаюсь, что со всем этим можно жить (хотя бы потому что сам долго пишу на js), но с современным пониманием ооп — javascript имплементация стыкуется слабо, эдакая «неизвестная земля» на фоне имплементаций в остальных языках.
                                                                                                • 0
                                                                                                  Отсутствие интерфейсов не отменяет наличие полиморфизма
                                                                                            • 0
                                                                                              каким образом вы сможете избежать callback-ов, Deferred-oв или yield-ов?

                                                                                              Эм… там все делается через Handler…


                                                                                              В twisted нету errback-ов? Все само ловится через try/catch?

                                                                                              За twisted не скажу, tornado кидает ошибки и, если разработчик нигде ее не обработал, выкинет в лог.

                                                                                              • +1
                                                                                                Неблокирующий запрос к базе данных внутри Handler-а как будете делать? Взять momoko или motor например, кто будет обрабатывать результат выполнения? Без yield или callback получится?
                                                                                                А вообще тема конечно холиварная и вброс удачный. Для меня лично нет никакой неопределенности какой язык лучше. Писать мне приятно на JS на нем мысль сама вытекает — но это просто дело привычки, код обычно элегантнее, опрятнее и быстрее на питоне(но разумеется не всегда). Оба языка имеют и давно доказали свое право на существование, и у обоих языков рыльце в пушку, в питоне как и в js не все так идеально и радужно как хотелось бы.
                                                                                            • 0
                                                                                              Расскажите о своем опыте?… «перескакивать» назад, на более комфортный язык?
                                                                                              Мой опыт такой:
                                                                                              Года 4 назад я подумал о переходе на ноду, в итоге начал тестовый проект на ноде, что-бы пощупать как оно, асинхронность из «коробки», да и скорость v8 выше. Через несколько дней я понял что оно не сильно лучше чем в питоне (благо я наелся калбеков в питоне к этому времени), а самое главное что асинхронщина нужна далеко не всегда (хотя все* сейчас пытаются её использовать для всего подряд).
                                                                                              В итоге я вернулся в питон. И периодический наблюдаю подобные статьи об уходе с ноды.
                                                                                              Я по прежнему активно использую ноду, но только в качестве тулинга.
                                                                                              • –13
                                                                                                Что ЭТО вообще делает на главной Хабра?

                                                                                                Ага, всего лишь горстка приличных SQL пакетов. Позднее вы поймете, что все существующие ORM инструменты никуда не годятся и то, что базовый драйвер — это лучший выбор.


                                                                                                Во-первых, вы так говорите «базовый драйвер», как будто это что-то плохое.
                                                                                                Во-вторых, ну уж точно всяких ORM-ов под ноду написано не меньше, чем под всё остальное. Возможно, вместе взятое.

                                                                                                Вы никогда не станете мастером того, что движется с такой, ломающей голову скоростью.


                                                                                                У меня плохая новость для всех вас. Сегодня становится мастером тот, кто умеет изменяться «с ломающей голову скоростью».

                                                                                                Это способ писать код, который выглядит более-менее синхронно, без сумасшедшей 'callback' логики.


                                                                                                Этот пассаж я даже не знаю как комментировать. А что, callback в промисе чем-то отличается от остальных?

                                                                                                Последней каплей было то, что я обнаружил отсутствие стандартов.


                                                                                                Что, серьёзно, кто-то жалуется на недостаточное количество стандартов в JS?

                                                                                                Это всё накаляет… Никто не может сказать, как написать стандартизированный JavaScript-код. Просто забейте в гугле «JavaScript Coding Standards» и вы поймете, что я имею ввиду.


                                                                                                Вероятно, автор имеет в виду то, что он не понимает разницы между кодстайлом и стандартом.

                                                                                                Это проверенный временем вариант с великолепными стандартами, библиотеками, легкой отладкой и стабильной работой.


                                                                                                А напомните инструмент легкой отладки серверного Питона кто-нибудь.
                                                                                                • +3
                                                                                                  У меня плохая новость для всех вас. Сегодня становится мастером тот, кто умеет изменяться «с ломающей голову скоростью».

                                                                                                  Назовите топ-5 полезных библиотек для node.js, которые недавно вышли. Потом расскажите, как они работают и какие у них сложности.


                                                                                                  Суть в том, что серьезных сложных библиотек в других языках программирования не появляется так много, как в случае node.js.


                                                                                                  Что, серьёзно, кто-то жалуется на недостаточное количество стандартов в JS?

                                                                                                  Когда стандартов много, их нет. Возможно, вы не знали об этом?


                                                                                                  Вероятно, автор имеет в виду то, что он не понимает разницы между кодстайлом и стандартом.

                                                                                                  Вероятно, автор называет кодстайл стандартом. Он же работает на Python, тут есть pep8.


                                                                                                  А напомните инструмент легкой отладки серверного Питона кто-нибудь.

                                                                                                  Как насчет pydb? PyCharm Ultimate версии отлично умеет в удаленную отладку, только path mapping настроить.

                                                                                                  • +4
                                                                                                    > Назовите топ-5 полезных библиотек для node.js, которые недавно вышли.

                                                                                                    Ммм. Вообще-то весь nodejs недавно вышел. Ну ок, скажем, React, eslint, jsdoc3, gulp, swagger-tools
                                                                                                    Алаверды, назовите топ-5 полезных библиотек для питона, которые недавно вышли.

                                                                                                    > Суть в том, что серьезных сложных библиотек в других языках программирования не появляется так много, как в случае node.js.

                                                                                                    Это проблема nodejs — в нём появляется слишком много серьёзных сложным библиотек? Серьёзно?

                                                                                                    > Когда стандартов много, их нет. Возможно, вы не знали об этом?

                                                                                                    Имею некоторое представление. Стандарт на ECMAScript как бы один — тот, который TC39 разрабатывает.

                                                                                                    > Как насчет pydb? PyCharm Ultimate версии отлично умеет в удаленную отладку, только path mapping настроить.

                                                                                                    Сюрприз — WebStorm точно такую же удалённую отладку Nodejs имеет.
                                                                                                  • 0
                                                                                                    Пройдите на оригинал статьи и на понятном английском объясните это все автору статьи, сопровождая это ORLY. Посмотрим че из этого выйдет. Это перевод, не понято кому вы это все доказываете тут. Переводчику?
                                                                                                    • +4

                                                                                                      Хватило бы одной совы, честное слово :)

                                                                                                    • 0

                                                                                                      Интересный пример асинхронщины:


                                                                                                      • +2
                                                                                                        Автор судя по статье просто нытик какой-то. Он даже не касался утечек памяти и оптимизаций. А весь баттхёрт у него в итоге из-за непонимания nodejs как платформы. Control-flow теперь легко управлять с помощью co, ES6 в node@6 поддерживается уже практически полностью. Если он хороши пишет на питоне, ну и писал бы на питоне.
                                                                                                        • +1
                                                                                                          А кстати скажите мне какой плюс nodejs в сравнении скажем с использованием asyncio или tornado на python? Не в производительности и синтаксисе, а именно архитектурно есть разница?
                                                                                                          • +2
                                                                                                            Исключая всякие полезные мелочи, типа возможности застримить тело POST-запроса — основное отличие ноды от async/await фреймворков в питоне/C#/вотэва в том, что цель последних — замаскировать асинхронность; ты пишешь типа синхронный код, вся магия скрыта в самом фреймворке. В ноде это не так. Вся асинхронность явно вынесена наружу, и ты должен писать код с пониманием того, как оно работает.
                                                                                                            • 0
                                                                                                              Вы видимо непонимаете что такое async/await (который, кстати, есть и в яваскрипте).
                                                                                                              Про питон не скажу, но и в C# и в js async await просто удобная синтаксическая конструкция. Того же результата можно добиться и «старыми» методами — .then() в js, .ContinueWith() в C#. И в js и в C# необходимо понимать что пишешь асинхронный код (который с async/await просто выглядит чуть удобнее). Ни C# ни js не маскируют асинхронность ни в каком виде (это попросту невозможно), а просто дают инструмент для более удобной работы с ней.

                                                                                                              • 0
                                                                                                                > Вы видимо непонимаете что такое async/await (который, кстати, есть и в яваскрипте).

                                                                                                                Ну вы держите меня в курсе.

                                                                                                                > Ни C# ни js не маскируют асинхронность ни в каком виде (это попросту невозможно), а просто дают инструмент для более удобной работы с ней.

                                                                                                                … причём под «более удобной» работой подразумевается написание «как будто» синхронного кода. Да, именно это я и имею в виду. Это «удобство» вот для тех самых разработчиков, которые боятся всего нового как огня.

                                                                                                                В nodejs можно написать, например, так (в нотации vow):

                                                                                                                vow.all([
                                                                                                                    fetch(url1).timeout(200).then((res) => res.json()),
                                                                                                                    doAsyncOperation1().timeout(100).then((res1) => {
                                                                                                                        return doAsyncOperation2(res1.url).timeout(100);
                                                                                                                    })
                                                                                                                ]).spread((res, res2) => {
                                                                                                                    // do something valuable
                                                                                                                });
                                                                                                                


                                                                                                                Т.е. реально контролировать время и порядок исполнения асинхронных операций, в т.ч. свободно отстреливать их по таймаутам. При этом в ноде асинхронно реально ВСЁ.

                                                                                                                И это для фронтендовских задач, которые обычно заключаются в построении ответа по куче источников, как бы must have. Писать в async/await стиле — просто не понимать, что за механизм тебе дали в руки.
                                                                                                                • 0
                                                                                                                  — Писать в async/await стиле — просто не понимать, что за механизм тебе дали в руки.

                                                                                                                  Вы издеваетесь? То же самое что и в вашем коде с async/await:

                                                                                                                  main () {

                                                                                                                  let promise1 = getUsersAsync({timeout: 200});
                                                                                                                  let promise2 = getOrganizationsAsync({timeout: 1500});

                                                                                                                  let [users, organizations] = await Promise.all([promise1, promise2]);

                                                                                                                  // работаем с users, organizations

                                                                                                                  }

                                                                                                                  async getUsersAsync(configuration) {

                                                                                                                  let r = await fetch(usersUrl, configuration);

                                                                                                                  return r;

                                                                                                                  }

                                                                                                                  async getOrganizationsAsync(configuration) {

                                                                                                                  let result1 = await fetch(url1, configuration);
                                                                                                                  let result2 = await processAsync(result1);

                                                                                                                  return result2;

                                                                                                                  }
                                                                                                                • +1
                                                                                                                  Ни C# ни js не маскируют асинхронность ни в каком виде (это попросту невозможно)

                                                                                                                  В JS это не просто возможно, но я бы и настоятельно рекомендовал использовать. Приведу пример. Пусть у нас есть модуль:


                                                                                                                  module.exports.say = ( greeting , user ) => {
                                                                                                                     console.log( greeting + ', ' + user.name + '!' )
                                                                                                                  }

                                                                                                                  Казалось бы, зачем ему знать что либо про асинхронность? Но нет, если мы хотим получать имя пользователя в том числе и асинхронно, то нам придётся изменить и этот простой модуль:


                                                                                                                  module.exports.say = async ( greeting , user ) => {
                                                                                                                      console.log( greeting + ', ' + ( await user.name ) + '!' )
                                                                                                                  }

                                                                                                                  И теперь, если у нас уже есть имя пользователя, то нужно писать такой вот странный код вызова:


                                                                                                                  var greeter = requiire( './greeter' )
                                                                                                                  async () => {
                                                                                                                      await greeter.say( 'Hello' , { name : Promise.resolve( 'Anonymous' ) } )
                                                                                                                      await greeter.say( 'Bye' , { name : Promise.resolve( 'Anonymous' ) } )
                                                                                                                  }().catch( error => {
                                                                                                                      console.error( error )
                                                                                                                      process.exit( 1 )
                                                                                                                  } 

                                                                                                                  Вместо более естественного:


                                                                                                                  var greeter = requiire( './greeter' )
                                                                                                                  greeter.say( 'Hello' , { name : 'Anonymous' } )
                                                                                                                  greeter.say( 'Bye' , { name : 'Anonymous' } )

                                                                                                                  Хорошо хоть require пока синхронный. :-D


                                                                                                                  async|await, generators, promises — как вирусы, они стремительно распространяются по вашему приложению, заставляя в каждую функцию вносить странные изменения. Стоит одну функцию сделать асинхронной и все вызывающие её функции тут же заразятся этой заразой. И никакая функция, которая вызывает хоть какую-то другую функцию или обращается к полям каких либо объектов, не застрахована от такого "переписывания генома".

                                                                                                                  • +1
                                                                                                                    — В JS это не просто возможно, но я бы и настоятельно рекомендовал использовать. Приведу пример.
                                                                                                                    А где пример? Покажите как асинхронный код можно использовать ничего не зная о том что он асинхронный (вроде вызова к серверу, который неизвестно когда выполнится и выполнится ли вообще).

                                                                                                                    Приведенный вами пример слишком синтетический, поэтому дать какие-то комментарии по нему проблематично. greeter.say — это не асинхронная функция. Вот код который вызывает greeter.say может быть асинхронным (если надо получить пользователя с сервера). А может быть и синхронным (если пользователь уже был получен).

                                                                                                                    А вообще nodejs пропагандирует асинхронность не просто потому что делать нечего. А для того чтобы не блокировать поток. Если все вызовы будут синхронными тогда на каждый такой вызов будет блокироваться поток выполнения, что значит что на 1 инстансе ноды нельзя будет выполнить более 1 запроса одновременно (все запросы будут выполняться последовательно), а это очевидно никому не нужно.
                                                                                                                    • +1

                                                                                                                      Вот пример.:


                                                                                                                      var Future = require( 'fibers/future' );
                                                                                                                      var Fetch = require( 'fetch-promise' );
                                                                                                                      
                                                                                                                      module.exports = class Transport {
                                                                                                                      
                                                                                                                          constructor({ uri }) {
                                                                                                                              this.uri = uri
                                                                                                                          }
                                                                                                                      
                                                                                                                          fetch() {
                                                                                                                              return Future.fromPromise( Fetch( this.uri ) ).wait();
                                                                                                                          }
                                                                                                                      
                                                                                                                          fetchJSON() {
                                                                                                                              return JSON.parse( this.fetch().buf );
                                                                                                                          }
                                                                                                                      
                                                                                                                          fetchData() {
                                                                                                                              return this.fetchJSON().data;
                                                                                                                          }
                                                                                                                      };

                                                                                                                      И нет, системный поток не будет заблокирован. Заблокирована будет лишь текущая "задача" (например, обработка одного клиентского запроса). И пока она заблокирована, процессор будет заниматься другими задачами (например, другие запросы обрабатывать).

                                                                                                            • +1
                                                                                                              Во многом согласен с тезисами, но продолжаю использовать nodejs дальше как основной инструмент. Это весело. Среда очень быстро изменяется, постоянно узнаешь о новых подходах, пересматриваешь привычки, становишься гибче. Но надо понимать, что nodejs достаточно специфичен и не подходит для многих проектов.