В последнее время я занимался общим исследованием основных модулей Node.js и недавно взглянул на модуль util
. Я видел, как его использовали здесь и там в прошлом, но никогда особо не исследовал его. Я обнаружил несколько особых вариантов использования, но удобных функций. Вот краткое изложение каждого с некоторыми пояснениями и примерами. Как всегда, официальная документация тоже хороша.
В документации отмечается, что util
поддерживается для внутреннего использования, однако инструменты в нем достаточно общие, чтобы они также могли принести пользу разработчикам приложений и модулей. Я видел в NPM множество пакетов, которые удовлетворяют схожие потребности, поэтому всегда интересно посмотреть, что можно сделать, используя основные модули и избегая лишних зависимостей.
Вот полный список util
функций (без учета устаревшего):
- util.debuglog: простое средство ведения журнала отладки, которое можно включить / отключить с помощью переменной среды.
- util.deprecate: Оберните общедоступные функции простым уведомлением о прекращении поддержки.
- util.format: средство форматирования строк (ala. sprintf, printf и т. д.)
- util.inherits: обновляет прототип объекта, чтобы он унаследовал от другого.
- util.inspect: более эффективная регистрация данных с поддержкой цвета, обхода глубины объекта и других параметров.
util.debuglog
Ведение журнала - одна из тех вещей, которая может легко выйти из-под контроля, иногда случайно совершаться и может раздражать, когда вы этого не хотите. util.debuglog
предоставляет простую функцию ведения журнала, которая явно включается с помощью переменной среды NODE_DEBUG
. Вот небольшой пример ...
const util = require('util'); const log = util.debuglog('API'); const myObject = { url: 'http://eran.sh', coffee: true, address: { address1: '123 Fake St.', address2: 'Gainesville, FL', }, tags: ['red', 'banana', 'golf'] }; log(myObject);
Перед регистрацией чего-либо вызывается util.debuglog
, которому присваивается тег, соответствующий модулю, в котором он будет использоваться. Затем он возвращает функцию, которую можно вызвать для регистрации чего-либо в вашем приложении.
По умолчанию, ничего не будет регистрироваться выше, поскольку util.debuglog
по умолчанию молчит. Только когда приведенный выше сценарий будет запущен с NODE_DEBUG=API node app.js
, мы действительно увидим вывод в консоли. Это позволяет оставить полезный журнал отладки в коде, не загромождая консоль и не влияя непреднамеренно на производительность.
После того, как переменная среды установлена, ведение журнала будет выглядеть примерно так:
Помимо имени модуля также отображается идентификатор процесса. Это может быть полезно при работе с несколькими процессами.
Если вам кажется, что util.debuglog
слишком ограничен, существует множество более сложных решений для ведения журнала. У меня были хорошие результаты с winston, но есть и многие другие.
Подробнее на util.debuglog
здесь.
util.deprecate
При создании приложения или инструмента, на которые полагаются другие разработчики, отказ от рекомендаций является необходимой практикой, которая позволяет вам, сопровождающему, продолжать развивать API вашего инструмента, не удаляя при этом случайно что-то, от чего зависят другие. util.deprecate
настолько просто, насколько возможно. Допустим, у вас есть пакет на NPM, который предоставляет разработчикам функцию:
function capitalizeAndJoin(inputArray = []) { return inputArray .map(s => s.toString().toUpperCase()) .join(',') } module.exports = capitalizeAndJoin;
Вот код нашего разработчика, использующий этот модуль:
const capitalizeAndJoin = require(‘./capitalize-and-join’); const demoArray = [‘hello’, ‘test’, ‘wee’, 8]; console.log(capitalizeAndJoin(demoArray)) // Outputs: // HELLO,TEST,WEE,8
Если мы решили отказаться от функции capitalizeAndJoin
, мы можем легко это сделать с помощью util.deprecate
.
const util = require('util'); // ... module.exports = util.deprecate( capitalizeAndJoin, 'This function has been deprecated. Use something else instead.' );
Обернув нашу функцию util.deprecate
и предоставив предупреждающее сообщение, разработчики получат четкое указание на то, когда функция может быть удалена. Вот как это выглядит:
Программа по-прежнему работает в обычном режиме, однако отображается DeprecationWarning
.
Подробнее на util.deprecate
здесь.
util.format
Если вы знакомы с PHP или другими языками, которые включают утилиты форматирования строк, отсутствие функции printf
в JavaScript может вам не понравиться. К счастью, Node.js предоставляет эту функцию через util.format
для простоты использования. Пример вполне может говорить сам за себя:
const util = require('util'); const name = 'Eran'; const daysLeft = 4; const message = util.format( 'Hello, %s! You have %d days remaining on your subscription.', name, daysLeft ); console.log(message); // Outputs: // Hello, Eran! You have 4 days remaining on your subscription.
util.format
принимает строку формата, которая может включать токены, такие как %s
, %d
и некоторые другие. Это позволяет записывать строку без непосредственной интерполяции переменных. Это означает, что строка может храниться отдельно или извлекаться из локализованной группы сообщений, сохраняя при этом ваши переменные отдельно.
Подробнее на util.format
здесь.
util.inherits
В мире до классов ES2015 (любите их или ненавижу их) наследование было чем-то, что нужно было делать вручную в JavaScript. Хотя это требовалось не для всего, это был шаблон, который иногда поощрялся в Node.js. Например, при написании эмиттера событий необходимо было импортировать Node.js EventEmitter, а затем наследовать от него для собственного использования. Обычно это выглядит так:
const util = require('util');
const EventEmitter = require('events');
function MyStream() {
EventEmitter.call(this);
}
util.inherits(MyStream, EventEmitter);
Теперь, когда JavaScript поддерживает наследование в традиционном смысле класса ООП, рекомендуемым способом наследования от суперкласса является использование extends
без необходимости util.inherits
…
const EventEmitter = require('events');
class MyStream extends EventEmitter {
constructor() {
super();
}
}
Подробнее на util.inherits
здесь.
util.inspect
Мы заканчиваем еще одним инструментом отладки, util.inspect
аналогичен использованию console.log
для регистрации структур данных. Он возвращает форматированное строковое представление для удобства использования человеком. Это мало чем отличается от вывода, который вы получаете при передаче объекта в console.log
, однако он дает вам больше контроля. Ознакомьтесь с примерами ниже…
const util = require('util'); const myObject = { url: 'http://eran.sh', coffee: true, address: { address1: '123 Fake St.', address2: 'Gainesville, FL', }, tags: ['red', 'banana', 'golf'] }; console.log(util.inspect(myObject))
Поведение по умолчанию даст вам что-то вроде этого:
Inspect принимает второй параметр, объект конфигурации, который позволяет настраивать вывод. Некоторые интересные предметы включают…
const inspectOpts = { showHidden: true, // Display non-enumerable properties depth: 1, // How many nested properties deep should read colors: true, // Display output in color breakLength: 1 // # of items to be listed on a single line };
Примечание. Доступны дополнительные параметры, полный список см. в документации.
Возможность контролировать глубину возвращаемых данных может быть чрезвычайно полезной для предотвращения чрезмерного журнала и затруднения поиска данных, которые вы ищете, что делает util.inspect
отличным инструментом в вашем распоряжении.
Подробнее на util.inspect
здесь.
Единый регистратор для ленивых…
Чтобы довести некоторые из этих концепций отладки до логического завершения, давайте рассмотрим пример, в котором мы можем использовать util.debuglog
и util.inspect
для создания простого многоразового модуля для использования в нашем приложении.
simple-logger.js
const { debuglog, inspect } = require('util'); const defaultOptions = { depth: 1, // How many nested properties deep should read colors: true, // Display output in color breakLength: 20 // # of items to be listed on a single line }; function getLogger(tagName = 'APP', overrideOptions = {}) { const logger = debuglog(tagName); const inspectOptions = Object.assign( {}, defaultOptions, overrideOptions ); return debugData => logger(inspect(debugData, inspectOptions)) } module.exports = getLogger;
Теперь этот модуль можно импортировать в наш проект так…
const log = require('./simple-logger')(); const myObject = { // ... }; log(myObject);
Теперь мы можем классифицировать тег util.debuglog
, когда требуется модуль, или оставить его пустым, чтобы по умолчанию он был равен 'APP'
. У нас также есть некоторые настройки конфигурации по умолчанию для util.inspect
, чтобы добиться хорошего результата.
Использование подобного подхода позволяет вам безопасно оставить ведение журнала и использовать его только тогда, когда это необходимо, установив для переменной NODE_DEBUG
значение 'APP'
.
Спасибо за прочтение!
Это краткое изложение модуля util
. Если вам интересно узнать больше о том, что можно сделать с помощью основных модулей Node.js, я определенно рекомендую ознакомиться с документацией по API. Документация не только хорошо написана и поддерживается, но и практически гарантировано, что вы будете узнавать что-то новое каждый раз, когда погружаетесь в нее. Оно того стоит!