>  기사  >  웹 프론트엔드  >  Nodejs에서 쓰기 가능한 스트림이란 무엇입니까? 사용방법

Nodejs에서 쓰기 가능한 스트림이란 무엇입니까? 사용방법

青灯夜游
青灯夜游앞으로
2020-11-23 17:49:303327검색

Nodejs에서 쓰기 가능한 스트림이란 무엇입니까? 사용방법

관련 권장 사항: "nodejs 튜토리얼"

쓰기 가능한 스트림이란 무엇입니까

쓰기 가능한 스트림은 쓰기 가능한 스트림 프로그램을 통해 업스트림에서 흐르는 데이터를 소비하는 데 사용되는 장치로의 데이터 흐름을 추상화한 것입니다. 장치에 데이터를 쓰는 것은 일반적으로 로컬 디스크 파일이거나 TCP 또는 HTTP와 같은 네트워크 응답입니다.

이전에 사용된 예를 보세요

process.stdin.pipe(process.stdout);

*process.stdout*은 쓰기 가능한 스트림입니다. 프로그램은 읽기 가능한 스트림 process.stdin에 의해 전달된 데이터를 표준 출력 장치에 씁니다. 읽기 가능한 스트림에 대한 이해를 바탕으로 쓰기 가능한 스트림을 이해하는 것은 매우 간단합니다. 스트림은 방향성 데이터이며, 읽기 가능한 스트림은 데이터 소스이고, 쓰기 가능한 스트림은 대상이며, 중간에 있는 파이프라인 링크는 양방향입니다. 개울.

쓰기 가능한 스트림 사용

쓰기 가능한 스트림 인스턴스의 **write()** 메서드를 호출하여 쓰기 가능한 스트림에 데이터를 씁니다

const fs = require('fs');
const rs = fs.createReadStream('./w.js');
const ws = fs.createWriteStream('./copy.js');

rs.setEncoding('utf-8');
rs.on('data', chunk => {
  ws.write(chunk);
});

앞서 언급한 대로 읽기 가능한 스트림의 데이터 이벤트를 모니터링하여 읽기 가능한 스트림을 흐름 모드로 전환하려면 콜백 이벤트에서 쓰기 가능한 스트림의 write() 메서드를 호출하여 데이터가 쓰기 가능한 스트림 추상화 장치(현재 디렉터리의 copy.js 파일)에 기록되도록 합니다.

write() 메소드에는 세 개의 매개변수가 있습니다

  • chunk {String|Buffer}, 이는 쓰여질 데이터를 나타냅니다
  • encoding 쓰여진 데이터가 문자열인 경우 인코딩을 설정할 수 있습니다
  • callback 데이터가 작성된 후의 콜백 함수

사용자 정의 쓰기 가능 스트림

은 사용자 정의 읽기 가능 스트림과 유사합니다. 간단한 사용자 정의 쓰기 가능 스트림에는 두 단계만 필요합니다

  1. 스트림 모듈의 Writable 클래스를 상속합니다.
  2. Implementation_write() method

간단한 쓰기 가능 스트림을 구현하고 쓰기 가능 스트림에 전달된 데이터를 대문자로 변환한 다음 표준 출력 장치로 출력합니다(더 좋은 예는 로컬 디스크 파일에 쓰는 것일 수 있음) , 그러나 너무 많은 fs 작업이 포함되어 있어 번거롭습니다. 표준 출력 장치에 쓰는 것도 쓰기 동작입니다)

const Writable = require('stream').Writable

class OutputStream extends Writable {
    _write(chunk, enc, done) {
        // 转大写之后写入标准输出设备
        process.stdout.write(chunk.toString().toUpperCase());
        // 此处不严谨,应该是监听写完之后才调用 done
        process.nextTick(done);
    }
}

module.exports = OutputStream;

최종 쓰기 가능 스트림에 노출된 write() 메서드와 동일한 _write() 메서드가 있습니다. 매개변수 세 개, 함수는 비슷합니다

  • chunk decodeStrings가 false로 설정되지 않는 한 대부분 작성된 데이터는 버퍼입니다
  • encoding 데이터가 문자열인 경우 인코딩을 설정할 수 있으며, 버퍼 그렇지 않으면 개체 모드가 무시됩니다.
  • callback 데이터가 작성된 후 콜백 함수는 오류가 발생할 때 다음 데이터의 스트림에 알릴 수 있으며 오류 매개변수를 설정할 수도 있습니다

물론 실제로 _writev가 있습니다. () 구현 가능한 메서드인 이 메서드는 중단된 쓰기 대기열에 의해서만 호출되며 구현되지 않을 수 있습니다.

쓰기 가능한 스트림 인스턴스화

쓰기 가능한 스트림 클래스를 만든 후에는 이를 인스턴스화하여 사용할 수 있습니다. 쓰기 가능한 스트림을 인스턴스화할 때 선택할 수 있는 옵션이 여러 가지 있습니다. Knowledge

  • objectMode기본값은 false입니다. true로 설정하면 writable.write() 메서드는 문자열 및 버퍼 외에 모든 JavaScript 개체를 쓸 수 있습니다. 매우 유용한 옵션으로 나중에 변환 스트림 소개 시 자세히 소개하겠습니다
  • highWaterMark매회 기록되는 최대 데이터 양, 기본값은 Buffer의 경우 16kb, 기본값은 objectMode의 경우 16입니다.
  • decodeStrings 들어오는 데이터를 버퍼로 변환합니다. 기본값은 true입니다.

이렇게 하면 _write() 메서드에 의해 전달된 매개 변수의 의미를 더 명확하게 알 수 있으며 이해하는 데 도움이 됩니다. 나중에 소개되는 배압 메커니즘.

이벤트

읽기 가능한 스트림과 마찬가지로 쓰기 가능한 스트림에도 일반적으로 사용되는 여러 이벤트가 있습니다. 읽기 가능한 스트림을 기반으로 하면 비교적 이해하기 쉽습니다

  • pipe 읽기 가능한 스트림이 Pipe()를 호출할 때 메서드가 쓰기 가능한 스트림에 데이터를 전송하면 쓰기 가능한 스트림의 파이프 이벤트가 트리거됩니다
  • unpipe 읽기 가능한 스트림이 데이터 전송을 제거하기 위해 unpipe() 메서드를 호출하면 쓰기 가능한 스트림의 unpipe 이벤트가 트리거됩니다

이 두 이벤트는 쓰기 가능한 스트림에 데이터가 곧 도착하고 곧 끊어질 것임을 알리는 데 사용됩니다. 일반적인 상황에서는 거의 사용되지 않습니다.

writeable.write() 메소드에는 bool 반환 값이 있습니다. 앞서 언급한 highWaterMark처럼 써야 하는 데이터가 쓰기 가능한 스트림의 highWaterMark보다 큰 경우 데이터가 한 번에 쓰여지지 않습니다. 이때 writeable.write()는 false를 반환합니다. 처리할 수 있으면 true

drain을 반환합니다. .write()가 false를 반환했습니다. 일정 기간의 소화 후에 데이터의 백로그가 처리되었으며 새 데이터를 쓸 수 있을 때 트리거됩니다(drain의 원래 의미는 배수 및 고갈이며 매우 생생합니다)

除了 write() 方法可写流还有一个常用的方法 end(),参数和 write() 方法相同,但也可以不传入参数,表示没有其它数据需要写入,可写流可以关闭了。

finish 当调用 writable.end() 方法,并且所有数据都被写入底层后会触发 finish 事件

同样出现错误后会触发 error 事件

back pressure

了解了这些事件,结合上之前提到的可读流的一些知识,我们就能探讨一些有意思的话题了。在最开始我们提到过用流相对于直接操作文件的好处之一是不会把内存压爆,那么流是怎么做到的呢?

最开始我们可能会想到因为流不是一次性把所有数据载入内存处理,而是一边读一边写。但我们知道一般读取的速度会远远快于写入的速度,那么 pipe()  方法是怎么做到供需平衡的呢?

回忆一些基础知识,我们自己来实现一下 pipe() 方法的核心原理

  1. 可读流有流动和暂停两种模式,可以通过 **pause() resume() **方法切换
  2. 可写流的 **write() **方法会返回是否能处理当前的数据,每次可以处理多少是 hignWatermark 决定的
  3. 当可写流处理完了积压数据会触发 drain 事件

我们可以利用这三点来做到数据读取和写入的同步,还是使用之前的例子,但为了使消费速度降下来,我们各一秒再通知完成

class OutputStream extends Writable {
    _write(chunk, enc, done) {
        // 转大写之后写入标准输出设备
        process.stdout.write(chunk.toString().toUpperCase());
        // 故意延缓通知继续传递数据的时间,造成写入速度慢的现象
        setTimeout(done, 1000);
    }
}

我们使用一下自定义的两个类

const RandomNumberStream = require('./RandomNumberStream');
const OutputStream = require('./OutputStream');

const rns = new RandomNumberStream(100);
const os = new OutputStream({
    highWaterMark: 8 // 把水位降低,默认16k还是挺大的
});

rns.on('data', chunk => {
    // 当待处理队列大于 highWaterMark 时返回 false
    if (os.write(chunk) === false) { 
        console.log('pause');
        rns.pause(); // 暂停数据读取
    }
});

// 当待处理队列小于 highWaterMark 时触发 drain 事件
os.on('drain', () => {
    console.log('drain')
    rns.resume(); // 恢复数据读取
});

结合前面的三点和注释很容易看懂上面代码,这就是 pipe() 方法起作用的核心原理。数据的来源的去向我们有了大概了解,后面可以开始介绍数据的加工

  • duplex
  • transform

更多编程相关知识,请访问:编程学习课程!!

위 내용은 Nodejs에서 쓰기 가능한 스트림이란 무엇입니까? 사용방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제