노드를 사용하는 방법.js 흐름 (그리고 어떻게 피하는가!)

14634 단어 webdevjavascriptnode
내가 노드를 처음 이해하기 시작했을 때js streams, 나는 그것들이 매우 좋다고 생각한다.JavaScript 약속은 마음에 들지만 단 하나의 결과만 해결합니다.그러나 예상한 바와 같이 흐름은 일정한 데이터 흐름을 제공할 수 있습니다!
오늘날 기능성 반응식 프로그래밍이 매우 유행하고 있다.MobX, RxJS, Highland 같은 라이브러리.js는 전방 응용 프로그램의 구조를 간단하게 한다. 왜냐하면 데이터가 한 방향을 따라 일련의 파이프를 통해 아래로 흐르기 때문이다.
파이프를 통해 하나의 흐름을 다른 흐름으로 전송하여 첫 번째 흐름의 출력이 다음 흐름의 입력이 되도록 할 수 있다.응용 프로그램을 구축하는 아주 간결한 방법으로 들리죠?
약속을 사용하기 위해서 나는 이미 많은 자바스크립트 코드를 다시 썼다.시냇물은 진화의 다음 단계입니까?노드 흐름을 사용하기 위해 모든 프로그램을 다시 쓸 때가 되었습니까?(스포: 아니요!)

유닉스 파이프가 최고예요.


Linux(또는 Unix)에서 파이프를 사용하는 것을 좋아합니다.텍스트 파일을 가져오고 명령을 가져오고 출력을 다른 명령으로 가져오며 출력을 최종 텍스트 파일로 가져오는 것이 좋습니다.
다음은 명령줄에서 파이프 기능을 사용하는 예입니다.단어 목록이 포함된 텍스트 파일을 가져와 목록을 정렬하고 단어마다 나타나는 횟수를 계산한 다음 카운트를 정렬하여 처음 5개 단어를 표시합니다.
$ cat words.txt | sort | uniq -c | sort -nr | head -n5
이러한 명령을 이해하는 것은 중요하지 않습니다. 데이터가 '표준 입력' (또는 stdin 의 형식으로 모든 명령에 들어가고, 결과는 '표준 출력' (또는 stdout 의 형식으로 출력되는 것을 이해하면 됩니다.각 명령의 출력은 다음 명령의 입력이 됩니다.이것은 파이프 체인이다.
그래서 우리는 노드를 사용할 수 있다.js는 이 파이프 체인의 중간에 있습니까?우리는 당연히 할 수 있지!노드 흐름은 이를 실현하는 가장 좋은 방법이다.

파이프를 놓다


노드js streams는 대량의 데이터를 처리하는 좋은 방법으로 이 데이터들은 메모리의 용량을 초과한다.stdin에서 한 줄의 데이터를 읽고 처리한 다음 쓸 수 있습니다stdout.
예를 들어, 대문자로 된 노드 CLI 애플리케이션을 어떻게 만듭니까?보기에 매우 간단하다.stdin와 파이프를 직접 연결하기만 하면 되는 프로그램부터 시작합시다.이 코드는 거의 아무것도 하지 않습니다. (((stdout 유닉스 명령과 유사합니다.)
process.stdin.pipe(process.stdout);
이제 우리는 우리의 노드를 사용하기 시작할 수 있다.js 응용 프로그램은 개발 과정에서 다음과 같습니다.
$ cat words.txt | node capitalize.js | sort | uniq -c | sort -nr | head -n5
아주 간단하죠?우리는 아직 어떤 유용한 일도 하지 않았다.그렇다면 우리는 어떻게 각 줄을 수출하기 전에 이를 자본화합니까?

npm 구원하러 가기


우리 자신의 노드 흐름을 만드는 것은 좀 어렵기 때문에npm에 좋은 라이브러리가 있어서 이것을 더욱 쉽게 할 수 있습니다.cat라는 패키지를 a hacker snuck some code into it to steal bitcoins까지 자주 사용했습니다!)
우선, 우리는 event-stream 패키지를 사용할 것이다. 이것은 입력을 줄로 나누는 흐름이다. 이렇게 하면 우리는 한 줄의 데이터를 한 번에 처리할 수 있다.만약 우리가 이렇게 하지 않는다면, 우리는 여러 줄, 또는 일부 줄, 심지어 일부 유니코드 문자를 얻을 수 있을 것이다.split를 사용하면 훨씬 안전하고 매번 완전한 텍스트를 한 줄씩 사용할 수 있습니다.
우리는 split 라는 패키지를 사용할 수 있으며, 데이터를 처리하기 위해 흐름을 쉽게 만들 수 있다.우리는 입력 흐름에서 데이터를 수신하고 조작하여 출력 흐름으로 전송할 수 있다.
const split = require('split');
const through = require('through');

process.stdin
    .pipe(split())
    .pipe(
        through(function(line) {
            this.emit('data', line.toUpperCase());
        })
    )
    .pipe(process.stdout);
위 코드에 버그가 있습니다. 줄 바꾸기는 through 에서 제거되었기 때문에, 우리는 영원히 그것들을 추가하지 않을 것입니다.문제 없습니다. 코드를 분할하기 위해 우리가 원하는 임의의 재사용 가능한 흐름을 만들 수 있습니다.
const through = require('through');
const split = require('split');

function capitalize() {
    return through(function(data) {
        this.emit('data', data.toUpperCase());
    });
}

function join() {
    return through(function(data) {
        this.emit('data', data + '\n');
    });
}

process.stdin
    .pipe(split())
    .pipe(capitalize())
    .pipe(join())
    .pipe(process.stdout);
이거 귀엽지 않아요?나도 예전에 그렇게 생각했어.체인 파이프 목록을 통해 응용 프로그램의 주요 절차를 표현하는 것은 만족스러운 일이다.너는 너의 데이터가 split에서 몇 줄로 나뉘어 대문자로 다시 몇 줄로 연결되어 stdin로 흐르는 것을 쉽게 상상할 수 있다.

파이프를 따라 하수도로 들어가다


몇 년 동안 나는 줄곧 흐름을 이용하여 코드를 구성하려는 생각에 잠겨 있었다.일부 함수식 반응식 프로그래밍 개념을 빌려 데이터를 입력에서 출력으로 응용 프로그램에서 유동시키는 것이 우아한 것 같다.그런데 정말 코드를 간소화했나요?아니면 그냥 환각?우리는 정말 모든 업무 논리를 흐름 템플릿에 묶는 것에서 이득을 보았습니까?
보기보다 더 나빠.만약 우리가 파이프 중간에서 잘못을 저지르면 어떻게 합니까?우리는 파이프 밑에 오류 탐지기를 추가해서 오류를 포착할 수 있습니까?
process.stdin
    .pipe(split())
    .pipe(capitalize())
    .pipe(join())
    .pipe(process.stdout)
    .on('error', e => console.error(e)); // this won't catch anything!
아니요!오류가 파이프를 따라 전파되지 않기 때문에, 그것은 작동하지 않을 것이다.그것은 약속처럼 전화를 연쇄stdout하고 마지막에 .then전화를 던져서 중간의 모든 오류를 포착할 수 있다.아니요, 각 .catch 이후에 다음 사항을 확인하려면 오류 처리 프로그램을 추가해야 합니다.
process.stdin
    .pipe(split())
    .pipe(capitalize())
    .on('error', e => console.error(e))
    .pipe(join())
    .on('error', e => console.error(e))
    .pipe(process.stdout);
아이구!이 작업을 잊어버리면 파이핑에서 처리되지 않은 흐름 오류가 발생할 수 있습니다.스택 추적이 없습니다.당신이 생산 중에 디버깅을 할 때 행운을 빕니다.

결론과 건의


나는 과거에 시냇물을 좋아했지만 최근에 생각이 바뀌었다.현재, 나의 건의는 .pipe 흐름이 아니라 data 탐지기와 error 출력을 사용하는 것이지 through 파이프가 아니다.가능한 한 흐름의 수량을 최소화하고 이상적인 상황에서 입력 흐름과 출력 흐름만 있으면 된다.
다음은 다른 방법입니다. 우리는 위에서 같은 예를 쓸 수 있지만 모든 번거로움은 필요 없습니다.
const split = require('split');
const input = process.stdin.pipe(split());
const output = process.stdout;

function capitalize(line) {
    return line.toUpperCase();
}

input.on('data', line => {
    output.write(capitalize(line));
    output.write('\n');
});

input.on('error', e => console.error(e));
이것은 매우 간단하기 때문에, 나는 여전히 write 라이브러리를 사용하고 있으니 주의하십시오.그러나 그 후에 입력한 split 사건의 탐지기를 사용하여 데이터를 받을 것입니다.그리고 결과를 data로 출력write()에 보냅니다.
stdout 함수는 더 이상 흐름과 관련이 없다는 것을 주의하십시오.이것은 내가 흐르는 다른 곳에서 쉽게 그것을 다시 사용할 수 있다는 것을 의미한다. 이것은 정말 좋은 일이다.
나는 여전히 노드 흐름이 매우 재미있다고 생각하지만, 그것들은 자바스크립트의 미래가 아니다.만약 자세히 사용한다면, Node를 사용하여 매우 강력한 명령행 도구를 만들 수 있습니다.js.너무 하지 않도록 조심해라!
인터넷 개발에 관심이 있습니까?Subscribe to the Coding with Jesse newsletter!

좋은 웹페이지 즐겨찾기