Протоколы http и WebSocket Часть 9 работа с файловой системой Часть 10 стандартные модули, потоки, базы данных, node env
Скачать 1.79 Mb.
|
Часть 2: JavaScript, V8, некоторые приёмы разработки Какими JS-знаниями нужно обладать для Node.js-разработки? Предположим, вы только начали заниматься программированием. Насколько глубоко вам нужно изучить JavaScript для успешного освоения Node.js? Начинающему трудно достичь такого уровня, когда он приобретёт достаточную уверенность в своих профессиональных навыках. К тому же, изучая программирование, вы можете почувствовать, что не понимаете точно, где заканчивается браузерный JavaScript и начинается разработка для Node.js. Если вы находитесь в самом начале пути JavaScript-программиста, я посоветовал бы вам, прежде чем писать для Node.js, хорошо освоить следующие концепции языка: ● Лексические конструкции. ● Выражения. ● Типы. ● Переменные. ● Функции. ● Ключевое слово this. ● Стрелочные функции ● Циклы ● Области видимости. ● Массивы. ● Шаблонные строки. ● Применение точки с запятой. ● Работа в строгом режиме. На самом деле, этот список можно продолжать, но если вы всё это освоите, это значит, что вы заложите хорошую базу для продуктивной клиентской и серверной разработки на JavaScript. Следующие концепции языка, кроме того, весьма важны для понимания идей асинхронного программирования, которые являются одной из базовых частей Node.js. В частности, речь идёт о следующем: ● Асинхронное программирование и функции обратного вызова. ● Таймеры. ● Промисы. ● Конструкция async/await. ● Замыкания. ● Цикл событий. Существует множество материалов по JavaScript, которые позволяют начинающим освоить язык. Например, вот учебный курс автора данного руководства, вот весьма полезный раздел MDN, вот учебник сайта javascript.ru. Изучить базовые механизмы JavaScript можно на freecodecamp.com Выше мы говорили о том, что начинающих может беспокоить вопрос о том, где проходит граница между серверной и клиентской разработкой на JavaScript. Поговорим об этом. Различия между платформой Node.js и браузером Чем JS-разработка для Node.js отличается от браузерного программирования? Сходство между этими средами заключается в том, что и там и там используется один и тот же язык. Но разработка приложений, рассчитанных на выполнение в браузере, очень сильно отличается от разработки серверных приложений. Несмотря на использование одного и того же языка, существуют некоторые ключевые различия, которые и превращают два эти вида разработки в совершенно разные занятия. Надо отметить, что если тот, кто раньше занимался фронтендом, начинает изучать Node.js, у него имеется весьма серьёзная возможность довольно быстро освоить всё что нужно благодаря тому, что писать он будет на уже знакомом ему языке. Если к необходимости освоить новую среду добавляется ещё и необходимость изучить новый язык, задача значительно усложняется. Итак главное различие между клиентом и сервером заключается в окружении, для которого приходится программировать, в экосистемах этих сред. В браузере основной объём работы приходится на выполнение различных операций с веб-документами посредством DOM, а также — на использование других API веб-платформы, таких, скажем, как механизмы для работы с куки-файлами. Всего этого в Node.js, конечно, нет. Тут нет ни объекта document, ни объекта window, равно как и других объектов, предоставляемых браузером. В браузере, в свою очередь, нет тех программных механизмов, которые имеются в среде Node.js и существуют в виде модулей, которые можно подключать к приложению. Например, это API для доступа к файловой системе. Ещё одно различие между клиентской и серверной разработкой на JS заключается в том, что при работе в среде Node.js разработчик полностью контролирует окружение. Если только вы не занимаетесь разработкой опенсорсного приложения, которое может быть запущено где угодно, вы точно знаете, например, на какой версии Node.js будет работать ваш проект. Это очень удобно в сравнении с клиентским окружением, где вашему коду приходится работать в имеющемся у пользователя браузере. Кроме того, это означает, что вы можете, не опасаясь проблем, пользоваться новейшими возможностями языка. Так как JavaScript крайне быстро развивается, браузеры просто не успевают достаточно оперативно реализовать все его новшества. К тому же, далеко не все пользователи работают на самых свежих версиях браузеров. В результате разработчики, которые хотят использовать в своих программах что-то новое, вынуждены это учитывать, заботиться о совместимости их приложений с используемыми браузерами, что может вылиться в необходимость отказа от современных возможностей JavaScript. Можно, конечно, для преобразования кода в формат, совместимый со стандартом EcmaScript 5, который поддерживают все браузеры, воспользоваться транспилятором Babel, но при работе с Node.js вам это не понадобится. Ещё одно различие между Node.js и браузерами заключается в том, что в Node.js используется система модулей CommonJS , в то время как в браузерах можно наблюдать начало реализации стандарта ES Modules. На практике это означает, что в настоящее время в Node.js, для подключения внешнего кода, используется конструкция require(), а в браузерном коде — import. V8 и другие JavaScript-движки V8 — это название JavaScript-движка, используемого в браузере Google Chrome. Именно он отвечает за выполнение JavaScript-кода, который попадает в браузер при работе в интернете. V8 предоставляет среду выполнения для JavaScript. DOM и другие API веб-платформы предоставляются браузером. JS-движок независим от браузера, в котором он работает. Именно этот факт сделал возможным появление и развитие платформы Node.js. V8 был выбран в качестве движка для Node.js в 2009 году. В результате прямо-таки взрывного роста популярности Node.js V8 оказался движком, который в наши дни отвечает за выполнение огромного количества серверного JS-кода. Экосистема Node.js огромна. Благодаря этому V8 также используется, посредством проектов наподобие Electron , при разработке настольных приложений. Надо отметить, что, помимо V8, существуют и другие движки: ● В браузере Firefox применяется движок SpiderMonkey ● В Safari применяется JavaScriptCore (он ещё называется Nitro). ● В Edge используется движок Chakra Список JS-движков этим не ограничивается. Эти движки реализуют спецификацию ECMA-262, называемую ещё ECMAScript. Именно эта спецификация стандартизирует JavaScript. Свежую версию стандарта можно найти здесь Разработка JS-движков и стремление к производительности Движок V8 написан на C++, его постоянно улучшают. Он может выполняться на многих системах, в частности, на Mac, Windows и Linux. Здесь мы не будем говорить о деталях реализации V8. Сведения о них можно найти в других публикациях, в том числе — на официальном сайте V8 . Они со временем меняются, иногда — очень серьёзно. V8 постоянно развивается, то же самое можно сказать и о других движках. Это приводит, в частности, к росту производительности веб-браузеров и платформы Node.js. Производители движков для браузеров постоянно соревнуются, борясь за скорость выполнения кода, продолжается это уже многие годы. Всё это идёт на пользу пользователям и программистам. Интерпретация и компиляция JavaScript считается интерпретируемым языком, но современные движки занимаются далеко не только интерпретацией JS-кода. Они его компилируют. Это веяние можно наблюдать с 2009-го года, когда компилятор JavaScript был добавлен в Firefox 3.5, после чего и другие производители движков и браузеров переняли эту идею. V8 выполняет компиляцию JavaScript для повышения производительности кода. Со времени появления Google Maps в 2004-м году JavaScript эволюционировал, превратился из языка, на котором, для реализации интерактивных возможностей веб-приложений, обычно писали по несколько десятков строк, в язык, на котором пишут браузерные приложения, состоящие из тысяч или даже сотен тысяч строк кода. Такие приложения могут выполняться в браузере часами, что серьёзно отличается от старых сценариев использования JS, код на котором, например, мог применяться лишь для проверки правильности данных, вводимых в формы. В современных условиях компиляция кода имеет огромный смысл, так как, хотя выполнение этого шага может отложить момент запуска кода, после компиляции код оказывается гораздо более производительным, чем тот, который обрабатывался бы исключительно интерпретатором и запускался бы быстрее, но работал бы медленнее. Теперь, обсудив некоторые положения, касающиеся JS-движков, интерпретации и компиляции кода, перейдём к практике. А именно, поговорим о том, как завершать работу Node.js-приложений. Выход из Node.js-приложения Существует несколько способов завершения работы Node.js-приложений. Так, при выполнении программы в консоли, завершить её работу можно, воспользовавшись сочетанием клавиш ctrl+c. Но нас больше интересуют программные способы завершения работы приложений. И начнём мы, пожалуй, с самой грубой команды выхода из программы, которую, как вы сейчас поймёте, лучше не использовать. Модуль ядра process предоставляет удобный метод, который позволяет осуществить программный выход из Node.js-приложения. Выглядит это так: process.exit() Когда Node.js встречает в коде такую команду, это приводит к тому, что его процесс мгновенно завершается. Это означает, что абсолютно всё, чем занималась программа, будет довольно грубо и безусловно прервано. Речь идёт о невызванных коллбэках, о выполняемых в момент выхода сетевых запросах, о действиях с файлами, об операциях записи в stdout или stderr. Если вас такое положение дел устраивает — можете этим методом пользоваться. При его вызове можно передать ему целое число, которое будет воспринято операционной системой как код выхода из программы. process.exit(1) По умолчанию этот код имеет значение 0, что означает успешное завершение работы. Другие коды выхода имеют другие значения, которые могут оказаться полезными для использования их в собственной системе для того, чтобы наладить взаимодействие одних программ с другими. Подробности о кодах завершения работы программ можно почитать здесь Код выхода, кроме того, можно назначить свойству process.exitCode. Выглядит это так: process.exitCode = 1 После того, как программа завершит работу, Node.js вернёт системе этот код. Надо отметить, что работа программы самостоятельно завершится естественным образом после того, как она выполнит все заданные в ней действия. Однако в случае с Node.js часто встречаются программы, которые, в идеальных условиях, рассчитаны на работу неопределённой длительности. Речь идёт, например, об HTTP-серверах, подобных такому: const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Hi!') }) app.listen(3000, () => console.log('Server ready')) Такая программа, если ничего не случится, в теории, может работать вечно. При этом, если вызвать process.exit(), выполняемые ей в момент вызова этой команды операции будут прерваны. А это плохо. Для завершения работы подобных программ нужно воспользоваться сигналом SIGTERM и выполнить необходимые действия с помощью соответствующего обработчика. Обратите внимание на то, что для использования объекта process не нужно ничего подключать с помощью require, так как этот объект доступен Node.js-приложениям по умолчанию. Рассмотрим следующий пример: const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Hi!') }) app.listen(3000, () => console.log('Server ready')) process.on('SIGTERM', () => { app.close(() => { console.log('Process terminated') }) }) Что такое «сигналы»? Сигналы — это средства взаимодействия процессов в стандарте POSIX (Portable Operating System Interface). Они представляют собой уведомления, отправляемые процессу для того, чтобы сообщить ему о неких событиях. Например, сигнал SIGKILL сообщает процессу о том, что ему нужно немедленно завершить работу. Он, в идеале, работает так же, как process.exit(). Сигнал SIGTERM сообщает процессу о том, что ему нужно осуществить процедуру нормального завершения работы. Подобные сигналы отправляются из менеджеров процессов, вроде upstart или supervisord, и из многих других. Отправить такой сигнал можно и из самой программы, воспользовавшись следующей командой: process.kill(process.pid, 'SIGTERM') Для успешного выполнения подобной команды нужно знать PID процесса, который планируется завершить. Чтение переменных окружения из Node.js Модуль ядра process имеет свойство env, которое даёт доступ ко всем переменным окружения, которые были заданы на момент запуска процесса. Вот пример работы с переменной окружения NODE_ENV, которая, по умолчанию, установлена в значение development: process.env.NODE_ENV // "development" Если, до запуска скрипта, установить её в значение production, это сообщит Node.js о том, что программа выполняется в продакшн-окружении. Подобным образом можно работать и с другими переменными среды, например, с теми, которые установлены вами самостоятельно. Часть 3: хостинг, REPL, работа с консолью, модули Хостинг для Node.js-приложений Выбор хостинга для Node.js-приложений зависит от ваших потребностей. Вот небольшой список вариантов хостинга, который вы можете изучить, приняв решение развернуть своё приложение и сделать его общедоступным. Сначала рассмотрим простые варианты, возможности которых ограничены, а потом — более сложные, но и обладающие более серьёзными возможностями. Самый простой вариант хостинга: локальный туннель Даже если вашему компьютеру назначен динамический IP-адрес или вы находитесь за NAT, вы можете развернуть на нём своё приложение и обслуживать запросы пользователей к нему, используя локальный туннель. Этот вариант подходит для быстрой организации тестирования, для того, чтобы устроить демонстрацию продукта, или для того, чтобы дать доступ к приложению очень маленькой группе людей. Для организации локальных туннелей есть очень хороший сервис, ngrok , доступный для множества платформ. Используя ngrok, достаточно выполнить команду вида ngrok PORT и указанный вами порт будет доступен из интернета. У вас при этом, если вы пользуетесь бесплатной версией сервиса, будет адрес в домене ngrok.io. Если же вы решите оформить платную подписку, вы сможете использовать собственные доменные имена, и, кроме того, сможете повысить безопасность решения (пользуясь ngrok, вы открываете доступ к своему компьютеру всему интернету). Ещё один инструмент, который можно использовать для организации локальных туннелей, называется localtunnel Среды для развёртывания Node.js-проектов, не требующие настройки Glitch Glitch — это интерактивная среда и платформа для быстрой разработки приложений, которая позволяет разворачивать их в поддоменах glitch.com. Собственные домены пользователей эта платформа пока не поддерживает, при работе с ней существуют некоторые ограничения , но она отлично подходит для работы над прототипами приложений. Дизайн Glitch выглядит довольно забавно (пожалуй, это можно записать в плюсы данной платформы), но это не некая «игрушечная», ограниченная донельзя среда. Здесь к вашим услугам возможность работы с Node.js, CDN, защищённое хранилище для конфиденциальной информации, возможности обмена данными с GitHub и многое другое. Проектом Glitch занимается та же компания, которая стоит за FogBugz и Trello (она же является одним из создателей StackOverflow). Я часто использую эту платформу для демонстрации приложений. Codepen Codepen — это замечательная платформа, вокруг которой сформировалось интересное сообщество. Здесь можно создавать проекты, включающие в себя множество файлов, и разворачивать их с использованием собственного домена. Бессерверные среды Бессерверные платформы позволяют публиковать приложения и при этом совершенно не думать о серверах, об их настройке или об управлении ими. Парадигма бессерверных вычислений заключается в том, что приложения публикуют в виде функций, которые реагируют на обращения к сетевой конечной точке. Подобный подход к развёртыванию приложений ещё называют FAAS (Functions As A Service, функция как услуга). Вот пара популярных решений в этой области: ● Фреймворк Serverless ● Библиотека Standard Оба эти проекта предоставляют разработчику некий уровень абстракции, позволяющий публиковать приложения на различных FAAS-платформах, например, на Amazon AWS Lambda, на Microsoft Azure и на Google Cloud. PAAS-решения PAAS (Platform As A Service, платформа как услуга) — это платформы, которые берут на себя заботу обо многих вещах, о которых, в обычных условиях, должен заботиться разработчик, развёртывающий приложение. Zeit Now Zeit — это интересный вариант для развёртывания приложений. Развёртывание, при использовании этой платформы, сводится к вводу в терминале команды now. Существует бесплатная версия Zeit, при работе с ней действуют некоторые ограничения. Есть и платная, более мощная версия этой платформы. Пользуясь Zeit, вы можете попросту не думать о том, что для работы вашего приложения нужен сервер. Вы просто разворачиваете приложение, а всё остальное находится в ведении этой платформы. Nanobox Создатели платформы Nanobox , в возможности которой входит развёртывание Node.js-приложений, называют её PAAS V2. Heroku Heroku — это ещё одна замечательная платформа для размещения Node.js-приложений. Вот хорошая статья о том, как с ней работать. Microsoft Azure Azure — это облачная платформа от Microsoft. В её документации есть раздел , посвящённый Node.js-приложениям. Платформа Google Cloud Google Cloud представляет собой замечательную среду для развёртывания Node.js-приложений. Вот соответствующий раздел её документации. VPS-хостинг Существует множество платформ, предоставляющих услуги VPS-хостинга . Общей чертой таких платформ является тот факт, что разработчик получает в своё распоряжение виртуальный сервер, самостоятельно устанавливает на него операционную систему (Linux или Windows), самостоятельно развёртывает приложения. Среди платформ, предоставляющих VPS-услуги, которых существует великое множество, можно отметить следующие, которыми я пользовался и которые мог бы порекомендовать другим: ● Digital Ocean ● Linode ● Amazon Web Services (в частности, хотелось бы отметить сервис AWS Elastic Beanstalk , облегчающий развёртывание приложений и управление ресурсами AWS). От себя добавим , что компания RUVDS тоже оказывает услуги VPS- хостинга . Мы лицензированы ФСТЭК , наши клиенты застрахованы AIG, у нас есть четыре дата - центра . Два расположены в Москве , на площадках ММТС -9 и MTW , один в швейцарских Альпах , и ещё один в Лондоне . Обычный сервер Ещё одно решение в области хостинга представляет собой покупку (или аренду, например, с помощью службы Vultr Bare Metal ) обычного сервера, установку на него Linux и другого ПО, подключение его к интернету и размещение на нём Node.js-приложений. Хостинг — тема огромная, но, надеемся, материалы этого раздела позволят вам выбрать именно то, что вам нужно. Теперь переходим к рассказу о работе с Node.js в режиме REPL Использование Node.js в режиме REPL Аббревиатура REPL расшифровывается как Read-Evaluate-Print-Loop (цикл «чтение — вычисление — вывод»). Использование REPL — это отличный способ быстрого исследования возможностей Node.js. Как вы уже знаете, для запуска скриптов в Node.js используется команда node, выглядит это так: node script.js Если ввести такую же команду, но не указывать имя файла, Node.js будет запущен в режиме REPL: node Если вы попробуете сейчас ввести такую команду в своём терминале, то в результате увидите примерно следующее: > node > Node.js теперь находится в режиме ожидания. Система ждёт, что мы введём в командной строке какой-нибудь JavaScript-код, который она будет выполнять. Для начала попробуем что-нибудь очень простое: > console.log('test') test undefined > Тут мы предложили Node.js выполнить команду, используемую для вывода данных в консоль. Первое значение, test, представляет собой то, что вывела команда console.log('test'). Второе значение, undefined, это то, что возвратила функция console.log(). После завершения выполнения команды появляется приглашение REPL, это означает, что мы можем ввести здесь новую команду. Автозавершение команд с помощью клавиши Tab REPL — это интерактивная среда. Если в процессе написания кода нажать клавишу Tab на клавиатуре, REPL попытается автоматически завершить ввод, подобрав, например, подходящее имя уже объявленной вами переменной или имя некоего стандартного объекта. Исследование объектов JavaScript Введите в командную строку имя какого-нибудь стандартного объекта JavaScript, например — Number, добавьте после него точку и нажмите клавишу Tab. REPL выведет список свойств и методов объекта, с которыми может взаимодействовать разработчик: Исследование объекта Number Исследование глобальных объектов Для того чтобы узнать, с какими глобальными объектам Node.js вы можете работать, введите в терминале команду global. и нажмите Tab. Исследование глобальных объектов Специальная переменная _ Переменная _ (знак подчёркивания) хранит результат последней выполненной операции. Эту переменную можно использовать в составе команд, вводимых в консоль. Команды, начинающиеся с точки В режиме REPL можно пользоваться некоторыми специальными командами, которые начинаются с точки. Вот они: ● Команда .help выводит справочные сведения по командам, начинающимся с точки. ● Команда .editor переводит систему в режим редактора, что упрощает ввод многострочного JavaScript-кода. После того, как находясь в этом режиме, вы введёте всё, что хотели, для запуска кода воспользуйтесь командой Ctrl+D. ● Команда .break позволяет прервать ввод многострочного выражения. Её использование аналогично применению сочетания клавиш Ctrl+C. ● Команда .clear очищает контекст REPL, а так же прерывает ввод многострочного выражения. ● Команда .load загружает в текущий сеанс код из JavaScript-файла. ● Команда .save сохраняет в файл всё, что было введено во время REPL-сеанса. ● Команда .exit позволяет выйти из сеанса REPL, она действует так же, как два последовательных нажатия сочетания клавиш Ctrl+C. Надо отметить, что REPL распознаёт ввод многострочных выражений и без использования команды .editor. Например, мы начали вводить код итератора: [1, 2, 3].forEach(num => { Если, после ввода фигурной скобки, нажать на клавишу Enter, REPL перейдёт на новую строку, приглашение в которой будет выглядеть как три точки. Это указывает на то, что мы можем вводить код соответствующего блока. Выглядит это так: ... console.log(num) ... }) Нажатие на Enter после ввода последней скобки приведёт к выполнению выражения. Если ввести в этом режиме .break, ввод будет прерван и выражение выполнено не будет. Режим REPL — полезная возможность Node.js, но область её применения ограничена небольшими экспериментами. Нас же интересует нечто большее, чем возможность выполнить пару команд. Поэтому переходим к работе с Node.js в обычном режиме. А именно, поговорим о том, как Node.js-скрипты могут принимать аргументы командной строки. Работа с аргументами командной строки в Node.js-скриптах При запуске Node.js-скриптов им можно передавать аргументы. Вот обычный вызов скрипта: node app.js Передаваемые скрипту аргументы могут представлять собой как самостоятельные значения, так и конструкции вида ключ-значение. В первом случае запуск скрипта выглядит так: node app.js flavio Во втором — так: node app.js name=flavio От того, какой именно способ передачи аргументов используется, зависит то, как с ними можно будет работать в коде скрипта. Так, для того, чтобы получить доступ к аргументам командной строки, используется стандартный объект Node.js process. У него есть свойство argv, которое представляет собой массив, содержащий, кроме прочего, аргументы, переданные скрипту при запуске. Первый элемент массива argv содержит полный путь к файлу, который выполняется при вводе команды node в командной строке. Второй элемент — это путь к выполняемому файлу скрипта. Все остальные элементы массива, начиная с третьего, содержат то, что было передано скрипту при его запуске. Перебор аргументов, имеющихся в argv (сюда входят и путь к node, и путь к выполняемому файлу скрипта), можно организовать с использованием цикла forEach: process.argv.forEach((val, index) => { console.log(`${index}: ${val}`) }) Если два первых аргумента вас не интересуют, на основе argv можно сформировать новый массив, в который войдёт всё из argv кроме первых двух элементов: const args = process.argv.slice(2) Предположим, при запуске скрипта, ему передали лишь один аргумент, в виде самостоятельного значения: node app.js flavio Обратиться к этому аргументу можно так: const args = process.argv.slice(2) args[0] Теперь попробуем воспользоваться конструкцией вида ключ-значение: node app.js name=flavio При таком подходе, после формирования массива args, в args[0] окажется строка name=flavio. Прежде чем пользоваться аргументом, эту строку надо разобрать. Самый удобный способ это сделать заключается в использовании библиотеки minimist , которая предназначена для облегчения работы с аргументами командной строки: const args = require('minimist')(process.argv.slice(2)) args['name'] //flavio Теперь рассмотрим вывод данных в консоль. Вывод данных в консоль с использованием модуля console Стандартный модуль Node.js console даёт разработчику массу возможностей по взаимодействию с командной строкой во время выполнения программы. В целом, это — то же самое, что объект console, используемый в браузерном JavaScript. Пожалуй, самый простой и самый широко используемый метод модуля console — это console.log(), который применяется для вывода передаваемых ему строковых данных в консоль. При этом, если передать ему объект, то он, перед выводом, будет преобразован к своему строковому представлению. Методу console.log() можно передавать несколько значений: const x = 'x' const y = 'y' console.log(x, y) После выполнения этой последовательности инструкций в консоль попадёт и значение x, и значение y. Для формирования сложных строк команда console.log() поддерживает использование подстановочных символов, которые, при выводе данных, заменяются на соответствующие им значения в порядке очерёдности. Например, вот команда, которая выводит текст My cat has 2 years: console.log('My %s has %d years', 'cat', 2) Рассмотрим особенности подстановочных символов: ● %s форматирует значение в виде строки. ● %d или %i форматируют значение в виде целого числа. ● %f форматирует значение в виде числа с плавающей точкой. ● %O используется для вывода строковых представлений объектов. Вот ещё один пример использования подстановочных символов: console.log('%O', Number) Очистка консоли Для очистки консоли используется команда console.clear() (её поведение в разных терминалах может различаться). Подсчёт элементов Сейчас мы рассмотрим полезный метод console.count(). Взгляните на этот код: const x = 1 const y = 2 const z = 3 console.count( 'The value of x is ' + x + ' and has been checked .. how many times?' ) console.count( 'The value of x is ' + x + ' and has been checked .. how many times?' ) console.count( 'The value of y is ' + y + ' and has been checked .. how many times?' ) Метод count() подсчитывает количество выводов строк и выводит результат рядом с ними. Используя этот метод можно, в следующем примере, посчитать яблоки и апельсины: const oranges = ['orange', 'orange'] const apples = ['just one apple'] oranges.forEach(fruit => { console.count(fruit) }) apples.forEach(fruit => { console.count(fruit) }) Вывод в консоль результатов трассировки стека Иногда бывает полезно вывести в консоль трассировку стека функции. Например, для того, чтобы ответить на вопрос о том, как мы попали в некое место программы. Сделать это можно с помощью такой команды: console.trace() Вот пример её использования: const function2 = () => console.trace() const function1 = () => function2() function1() Вот что произошло, когда я запустил этот код в режиме REPL: Trace at function2 (repl:1:33) at function1 (repl:1:25) at repl:1:1 at ContextifyScript.Script.runInThisContext (vm.js:44:33) at REPLServer.defaultEval (repl.js:239:29) at bound (domain.js:301:14) at REPLServer.runBound [as eval] (domain.js:314:12) at REPLServer.onLine (repl.js:440:10) at emitOne (events.js:120:20) at REPLServer.emit (events.js:210:7) Измерение времени, затраченного на выполнение некоего действия Измерить время, которое занимает, например, выполнение некоей функции, можно с использованием методов console.time() и console.timeEnd(). Выглядит это так: const doSomething = () => console.log('test') const measureDoingSomething = () => { console.time('doSomething()') //вызываем функцию и замеряем время, необходимое на её выполнение doSomething() console.timeEnd('doSomething()') } measureDoingSomething() Работа с stdout и stderr Как мы уже видели, команда console.log() отлично подходит для вывода сообщений в консоль. При её применении используется так называемый стандартный поток вывода, или stdout. Команда console.error() выводит данные в стандартный поток ошибок, stderr. Данные, отправляемые в stderr, попадают в консоль, хотя то, что выводится в этот поток, можно, например, перенаправить в файл журнала ошибок. Использование цвета при выводе данных в консоль Для того чтобы раскрасить выводимые в консоль тексты, можно воспользоваться escape-последовательностями, идентифицирующими цвета: console.log('\x1b[33m%s\x1b[0m', 'hi!') Если выполнить эту команду, например, в режиме REPL, текст hi будет выведен жёлтым цветом. Такой подход, однако, не особенно удобен. Для вывода в консоль цветных надписей удобно будет воспользоваться специализированной библиотекой, например — chalk . Эта библиотека, помимо цветового форматирования текстов, поддерживает и другие способы их стилизации. Например, с её помощью можно оформить текст полужирным, курсивным или подчёркнутым шрифтом. Для её установки из npm воспользуйтесь такой командой: npm install chalk Пользоваться ей можно так: const chalk = require('chalk') console.log(chalk.yellow('hi!')) Пользоваться командой chalk.yellow() гораздо удобнее, чем escape-последовательностями, да и текст программы при таком подходе читать гораздо легче. Для того чтобы узнать подробности о chalk, посмотрите страницу этой библиотеки на GitHub. Создание индикатора выполнения операции Индикатор выполнения операции (progress bar) может пригодиться в разных ситуациях. Для создания индикаторов выполнения, работающих в консоли, можно воспользоваться пакетом progress Установить его можно так: npm install progress Ниже показан пример кода, в котором создаётся индикатор, который можно использоваться для вывода сведений о некоей задаче, состоящей из 10 шагов. В нашем случае на выполнение каждого шага уходит 100 мс. После того, как индикатор заполнится, вызывается команда clearItnerval() и выполнение программы завершается. const ProgressBar = require('progress') const bar = new ProgressBar(':bar', { total: 10 }) const timer = setInterval(() => { bar.tick() if (bar.complete) { clearInterval(timer) } }, 100) Приём пользовательского ввода из командной строки Как сделать приложения командной строки, написанные для платформы Node.js, интерактивными? Начиная с 7 версии Node.js содержит модуль readline , который позволяет принимать данные из потоков, которые можно читать, например, из process.stdin. Этот поток, во время выполнения Node.js-программы, представляет собой то, что вводят в терминале. Данные вводятся по одной строке за раз. Рассмотрим следующий фрагмент кода: const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }) readline.question(`What's your name?`, (name) => { console.log(`Hi ${name}!`) readline.close() }) Здесь мы спрашиваем у пользователя его имя, а после ввода текста и нажатия на клавишу Enter на клавиатуре, выводим приветствие. Метод question() выводит то, что передано ему в качестве первого параметра (то есть — вопрос, задаваемый пользователю) и ожидает завершения ввода. После нажатия на Enter он вызывает коллбэк, переданный ему во втором параметре и обрабатывает то, что было введено. В этом же коллбэке мы закрываем интерфейс readline. Модуль readline поддерживает и другие методы, подробности о них вы можете узнать в документации, ссылка на которую приведена выше. Если вам, с использованием этого механизма, надо запросить у пользователя пароль, то лучше не выводить его, в ходе ввода, на экран, а показывать вместо введённых символов символ звёздочки — *. Для того чтобы это сделать, можно воспользоваться пакетом readline-sync , устройство которого похоже на то, как устроен модуль readline, и который поддерживает подобные возможности сразу после установки. Есть и ещё один пакет, предоставляющий более полное и абстрактное решение подобной проблемы. Это пакет inquirer . Установить его можно так: npm install inquirer С его использованием вышеприведённый пример можно переписать следующим образом: const inquirer = require('inquirer') var questions = [{ type: 'input', name: 'name', message: "What's your name?", }] inquirer.prompt(questions).then(answers => { console.log(`Hi ${answers['name']}!`) }) Пакет inquirer обладает обширными возможностями. Например, он может помочь задать пользователю вопрос с несколькими вариантами ответа или сформировать в консоли интерфейс с радиокнопками. Программисту стоит знать о наличии альтернативных возможностей по выполнению неких действий в Node.js. В нашем случае это стандартный модуль readline, пакеты readline-sync и inquirer. Выбор конкретного решения зависит от целей проекта, от наличия времени на реализацию тех или иных возможностей и от сложности пользовательского интерфейса, который планируется сформировать средствами командной строки. Система модулей Node.js, использование команды exports Поговорим о том, как использовать API module.exports для того, чтобы открывать доступ к возможностям модулей другим файлам приложения. В Node.js имеется встроенная система модулей, каждый файл при этом считается самостоятельным модулем . Общедоступный функционал модуля, с помощью команды require, могут использовать другие модули: const library = require('./library') Здесь показан импорт модуля library.js, файл которого расположен в той же папке, в которой находится файл, импортирующий его. Модуль, прежде чем будет смысл его импортировать, должен что-то экспортировать, сделать общедоступным. Ко всему, что явным образом не экспортируется модулем, нет доступа извне. Собственно говоря, API module.exports позволяет организовать экспорт того, что будет доступно внешним по отношению к модулю механизмам. Экспорт можно организовать двумя способами. Первый заключается в записи объекта в module.exports, который является стандартным объектом, предоставляемым системой модулей. Это приводит к экспорту только соответствующего объекта: const car = { brand: 'Ford', model: 'Fiesta' } module.exports = car //..в другом файле const car = require('./car') Второй способ заключается в том, что экспортируемый объект записывают в свойство объекта exports. Такой подход позволяет экспортировать из модуля несколько объектов, и, в том числе — функций: const car = { brand: 'Ford', model: 'Fiesta' } exports.car = car То же самое можно переписать и короче: exports.car = { brand: 'Ford', model: 'Fiesta' } В другом файле воспользоваться тем, что экспортировал модуль, можно так: const items = require('./items') items.car Или так: const car = require('./items').car В чём разница между записью объекта в module.exports и заданием свойств объекта exports? В первом экспортируется объект, который записан в module.exports. Во втором случае экспортируются свойства этого объекта. |