Menu

readline в Node.js: ввод пользователя в терминале

В Node.js нет функции prompt(). Чтобы задать пользователю вопрос в терминале, создайте интерфейс readline на process.stdin и вызовите question() или дождитесь ответа через await с readline/promises.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Чтобы прочитать ввод пользователя в Node.js, создайте интерфейс readline на process.stdin и спросите через rl.question(). В Node.js нет prompt(): браузерная версия открывает диалог, а у терминальной программы его нет. Современный вариант использует readline/promises, где await rl.question('Name? ') возвращает строку, которую ввёл пользователь. Закройте интерфейс, когда закончите, иначе программа так и будет ждать ввода.

question() вывел свой вопрос, дождался одной строки ввода и вернул её без перевода строки, так что программа вывела Next year you will be 37. Для нескольких вопросов дожидайтесь одного question() за другим.

readline question() с callback

Исходный API, который есть в любой версии Node.js, передаёт ответ в callback. Вложенные вопросы означают вложенные callback:

Программа вывела вопрос, затем You picked blue. Ответ это обычная строка, поэтому делайте trim перед сравнением: иначе пользователь, который поставил пробел после слова, получит 'blue ', а это не равно 'blue'.

Чтение по строкам

Чтобы обработать каждую строку до конца ввода, обходите интерфейс через for await. Так программа читает список, который ввёл пользователь (конец по Ctrl+D), или файл, переданный через node index.js < numbers.txt. Старый код делает то же через события: rl.on('line', fn) на каждую строку и rl.on('close', fn) в конце; цикл это та же пара событий, записанная сверху вниз:

Программа вывела 3 numbers, total 49, а цикл закончился сам, когда закончился ввод, поэтому close() не нужен. Добавьте четвёртую строку ввода, 1, и результат станет 4 numbers, total 50.

Прочитать весь stdin сразу

Для ввода из другой программы через пайп (cat data.txt | node index.js) проще прочитать всё одним вызовом. Файловый дескриптор 0 это стандартный ввод. Файл, сохранённый в Windows, может заканчивать строки на \r\n, поэтому делите по /\r?\n/, если ввод может прийти оттуда:

Программа вывела три товара в столбик. readFileSync(0) блокирует выполнение, пока ввод не закончится. Для скрипта, который читает пайп, и для тестов это нормально, а для интерактивного инструмента нет: пользователь ввёл бы всё до того, как увидел хоть один вопрос.

Что выбрать

Все четыре способа читают один и тот же стандартный ввод. Разница в том, когда ваш код получает текст: по одному ответу, по одной строке или всё в конце.

ЗадачаЧто использовать
Задать несколько вопросов по порядкуreadline/promises с await rl.question()
Поддержать версии Node.js до 17readline с callback в question()
Обрабатывать каждую строку по мере поступленияfor await (const line of rl)
Прочитать весь пайп или файл из stdinfs.readFileSync(0, 'utf8')
Значения известны до запуска программыВместо этого process.argv

Частые ошибки

Забыли rl.close(). Интерфейс держит стандартный ввод открытым, и программа не завершается после последнего вопроса. Закройте его, когда получите все ответы.

Ответ используют как число. Как и всё, что вводится в терминале, ответ это строка. '36' + 1 равно '361'; сначала преобразуйте через Number().

Несколько ответов через пайп на несколько вопросов. Когда ввод приходит из пайпа, а не с клавиатуры, readline читает его весь сразу, и строка, пришедшая до того, как задан её question(), теряется. Для ввода из пайпа используйте цикл for await или readFileSync(0).

Пропущена опция output. Без output: process.stdout question() не выводит вопрос, и пользователь смотрит на пустой терминал. Циклу по строкам она не нужна, потому что он ничего не выводит.

Часто задаваемые вопросы

Почему в Node.js prompt is not defined?

prompt() это функция браузера, которая открывает диалог, а у Node.js нет окна, где его открыть. В Node.js используйте readline или пакет вроде prompts или inquirer для меню и полей пароля.

Как прочитать пароль, не показывая его?

readline отображает каждую нажатую клавишу. Пакеты вроде prompts или @inquirer/password скрывают ввод; если делать это самому, придётся перевести терминал в raw режим через process.stdin.setRawMode(true) и обрабатывать каждую клавишу.

readline или process.argv?

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

Иллюстрация языков программирования Coddy

Учитесь программировать с Coddy

Начать