Node.js 표준 입력(readline) 정리

Lee Yechan·2023년 7월 17일
0

Language - javascript

목록 보기
5/8
post-thumbnail

이 글에서는…

Node.js에서 CommonJS와 ES6 방식으로 표준 입력을 받는 방법을 각각 정리한다.

함수 사용법만 설명한 블로그는 많지만, 그 함수가 어떤 함수인지는 설명해놓은 곳이 많이 없어 어떻게 표준 입력이 이뤄지는지 조금 더 자세히 알아보려고 한다.


Node.js는 입력이 왜 이렇게 불편한 거야?

https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_ARCHIVE.md#0.1.x

node.js는 2009년부터 그 역사를 시작해, 지금까지 사랑을 받고 있는 javascript 런타임 환경이다.

오늘 알아볼 readline 라이브러리도 그 역사가 2010년부터 시작했으니, 생각보다는 역사가 그리 길지 않은 것이다.

node.js 이전에는 javascript가 웹페이지로부터(form, prompt 등) 데이터를 얻어왔을 것이니, 그저 에러, 로깅 용으로 사용되는 console.error() 또는 console.log() 등의 출력 함수만 존재할뿐, 표준 입력 함수의 필요성을 잘 느끼지 못했을 것이다.

하지만 이제는 자바스크립트가 웹페이지만 스크립팅하는 시대는 지났으니, 프론트엔드부터 백엔드까지 풀스택으로 전천후로 사용할 수 있는 언어가 되었다.

이러한 역사 때문에 자바스크립트는 다른 언어들보다 표준 입력하는 방법이 상대적으로 복잡한 것으로 추측되나, 방법을 알고 나면 그렇게 어려운 것도 아니다.


CommonJS readline (require)

const readline = require('node:readline');
const { stdin: input, stdout: output } = require('node:process');

const rl = readline.createInterface({ input, output });
rl.on('line', function (line) {
  console.log(line);
  rl.close();
}).on('close', function () {
  process.exit();
});

위는 표준 입력을 받을 때 보편적으로 많이 사용하는 방법이다.

readline.createInterface()

readline.createInterface()는 입력 파라미터로 옵션들이 담긴 object를 받아, 인터페이스 인스턴스를 반환한다. 그중 위 코드에서 사용된 inputoutput은 각각 읽기 가능한 스트림, 쓰기 가능한 스트림을 받는다.

위에서는 읽기 가능한 스트림인 process.stdin으로부터 데이터를 읽고, process.stdout으로부터 데이터를 쓰는 인터페이스(rl)를 만든다.

rl.on(’line’, …)

.on()이라는 메서드명에서부터 유추할 수 있듯이, ‘line’이라는 이벤트가 발생했을 시 해야 할 일들을 콜백 함수로 받은 것이다.

‘line’ 이벤트는 input으로 지정된 스트림이 end-of-line 입력(\n\r\r\n)을 받으면 발생하고, rl.on()의 두 번째 인자로 넘겨준 함수는, 스트림 입력으로 받은 스트링 한 줄을 입력 파라미터로 받아 실행되게 된다.

rl.close()

rl.close()는 인터페이스 인스턴스의 문을 닫고, input과 output 스트림에 대한 권한을 내려놓도록 한다.

rl.close()를 해주지 않으면 계속 입력을 받으며, 입력을 받자마자 그 즉시 console.log()로 출력한다.

rl.on(’close’, …)

이것도 앞서 살펴본 rl.on(’line’, …)과 유사하게, 이 역시 ‘close’라는 이벤트가 발생했을 시 해야 할 일들을 콜백 함수로 받은 것이다.

‘close’ 이벤트는 다음 경우에 발생한다.

  • rl.close() 메서드가 호출되었을 때
  • input 스트림이 입력의 중단을 의미하는 입력을 받았을 때

이때의 콜백 함수는 아무 입력도 받지 않은 채로 실행된다.

process.exit()

node.js 프로세스를 수동으로 종료시키는 함수이다.


ES6 Modules readline (import)

import * as readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';

const rl = readline.createInterface({ input, output });
const answer = await rl.question('');
console.log(answer);
rl.close();

node:readline vs. node:readline/promises

promise-based API들을 사용하려면 아래 코드를,

import * as readline from 'node:readline/promises';

콜백과 sync API들을 사용하려면 아래 코드를 사용하면 된다.

import * as readline from 'node:readline';

다만, 현재(2023.07.) 기준으로 node:readline/promises 라이브러리는 experimental 단계이므로, 사용에 유의하는 것이 좋을 것이다.

2021년 10월에 만들어진 얼마 안된 라이브러리이며, experimental이라는 것은 ‘현재 기능이 디자인되고 있으며 추후 바뀔 것’이라는 의미이다.

rl.question()

쿼리(프롬프트)를 입력으로 받아, 사용자의 입력을 받는 함수이다.

주의할 점은 rl.close() 이후에 사용하면 rejected promise를 반환한다.

await 키워드를 붙여 비동기 처리한다.


정리

아직까지는 ES6 Modules를 이용한 방법보다 CommonJS를 이용한 방법이 주류를 이루고 있는 것 같다.

아무래도 ES6 support를 한 것도 아주 오래 되지 않았고, 변화의 과정 속에 있는 것으로 보인다.

지금으로써는 두 가지 방법을 다 알아놓은 뒤, 필요에 따라 둘 중 하나를 사용하는 것이 바람직할 듯 하다.


references

https://nodejs.org/api/readline.html

https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_ARCHIVE.md

https://velog.io/@exploit017/백준Node.js-Node.js-입력-받기

https://wooooooak.github.io/node.js/2018/09/26/Node.js-입력-받기/

https://velog.io/@ovzip/JavaScript-readline-사용하기

profile
이예찬

2개의 댓글

comment-user-thumbnail
2023년 7월 18일

정말 좋은 정보 감사합니다!

1개의 답글