programación avanzada nodejs - módulo central

1. camino

1 Obtenga el nombre base en la ruta

const path = require('path')

// console.log(__filename) // /Users/liuchongyang/Desktop/分享/网页读取本地文件/node.js

// 1 获取路径中的基础名称 
/**
 * 01 返回的就是接收路径当中的最后一部分 
 * 02 第二个参数表示扩展名,如果说没有设置则返回完整的文件名称带后缀
 * 03 第二个参数做为后缀时,如果没有在当前路径中被匹配到,那么就会忽略
 * 04 处理目录路径的时候如果说,结尾处有路径分割符,则也会被忽略掉
 */
 console.log(path.basename(__filename)) // node.js
console.log(path.basename(__filename, '.js')) // node
console.log(path.basename(__filename, '.css')) // node.js
console.log(path.basename('/a/b/c')) //c 
console.log(path.basename('/a/b/c/'))  // c

2 Obtenga el nombre del directorio de la ruta (ruta)

// 2 获取路径目录名 (路径)
/**
 * 01 返回路径中最后一个部分的上一层目录所在路径
 */
console.log(path.dirname(__filename)) // /Users/liuchongyang/Desktop/分享/网页读取本地文件
console.log(path.dirname('/a/b/c')) // /a/b

3 Obtener la extensión de la ruta

/**
 * 01 返回 path路径中相应文件的后缀名
 * 02 如果 path 路径当中存在多个点,它匹配的是最后一个点,到结尾的内容
 */
console.log(path.extname(__filename)) // .js
console.log(path.extname('/a/b')) // ''
console.log(path.extname('/a/b/index.html.js.css')) // .css
console.log(path.extname('/a/b/index.html.js.')) // .

4 ruta de análisis

/**
 * 01 接收一个路径,返回一个对象,包含不同的信息
 * 02 root dir base ext name
 */
const obj = path.parse('/a/b/c/index.html')
const obj = path.parse('/a/b/c/')
const obj = path.parse('./a/b/c/')
console.log(obj.name)

inserte la descripción de la imagen aquí

5 ruta de serialización

// 5 序列化路径
/* const obj = path.parse('./a/b/c/')
console.log(path.format(obj)) */

inserte la descripción de la imagen aquí

6 Determinar si la ruta actual es absoluta

/* console.log(path.isAbsolute('foo'))
console.log(path.isAbsolute('/foo'))
console.log(path.isAbsolute('///foo'))
console.log(path.isAbsolute(''))
console.log(path.isAbsolute('.'))
console.log(path.isAbsolute('../bar')) */

inserte la descripción de la imagen aquí

7 caminos de costura

console.log(path.join('a/b', 'c', 'index.html')) // a/b/c/index.html
console.log(path.join('/a/b', 'c', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '../', 'index.html')) // /a/b/index.html
console.log(path.join('/a/b', 'c', './', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '', 'index.html')) // /a/b/c/index.html
console.log(path.join('')) // .

8 rutas de normalización

// 8 规范化路径
console.log(path.normalize(''))
console.log(path.normalize('a/b/c/d'))
console.log(path.normalize('a///b/c../d'))
console.log(path.normalize('a//\\/b/c\\/d'))
console.log(path.normalize('a//\b/c\\/d'))

inserte la descripción de la imagen aquí

9 camino absoluto

// console.log(path.resolve())
/**
 * resolve([from], to)
 */
// console.log(path.resolve('/a', '../b'))
console.log(path.resolve('index.html')) // /Users/liuchongyang/Desktop/分享/网页读取本地文件/index.html

2. Buffer de variables globales

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

const b1 = Buffer.alloc(10) // 创建一个长度10的空buffer
const b2 = Buffer.allocUnsafe(10) // 方法创建一个指定大小的新缓冲区对象

console.log(b1) // <Buffer 00 00 00 00 00 00 00 00 00 00>
console.log(b2) // <Buffer c0 ff 83 0d 01 00 00 00 f0 a9>

// from 
const b1 = Buffer.from('中') // 创建一个buffer
console.log(b1) // <Buffer e4 b8 ad>

const b1 = Buffer.from([0xe4, 0xb8, 0xad])
console.log(b1) // <Buffer e4 b8 ad>
console.log(b1.toString())  // '中'


 const b1 = Buffer.from('中')
console.log(b1) // <Buffer e4 b8 ad>
console.log(b1.toString())  // '中'

const b1 = Buffer.alloc(3)
const b2 = Buffer.from(b1)

console.log(b1) // <Buffer 00 00 00>
console.log(b2) //<Buffer 00 00 00>

b1[0] = 1
console.log(b1) // <Buffer 01 00 00>
console.log(b2) // <Buffer 00 00 00>
let buf = Buffer.alloc(6)

// fill
 buf.fill(123)
console.log(buf) // <Buffer 7b 7b 7b 7b 7b 7b>
console.log(buf.toString()) // {
    
    {
    
    {
    
    {
    
    {
    
    {
    
    

// write 
 buf.write('123', 1, 4)
console.log(buf) // <Buffer 00 31 32 33 00 00>
console.log(buf.toString()) // '123'

// toString
buf = Buffer.from('你好')
console.log(buf) // <Buffer e4 bd a0 e5 a5 bd>
console.log(buf.toString('utf-8', 3, 9)) // 好

// slice 
 buf = Buffer.from('教育')
let b1 = buf.slice(-3)
console.log(b1) // <Buffer e8 82 b2>
console.log(b1.toString()) // 育

// indexOf
buf = Buffer.from('zce爱前端,爱、教育,爱大家,我爱所有')
console.log(buf)
console.log(buf.indexOf('爱qc', 4)) // -1

// copy 
let b1 = Buffer.alloc(6)
let b2 = Buffer.from('11')

b2.copy(b1, 3, 3, 6)
console.log(b1.toString())
console.log(b2.toString())

/* let b1 = Buffer.from('11')
let b2 = Buffer.from('教育')

let b = Buffer.concat([b1, b2], 9)
console.log(b)
console.log(b.toString()) */

// isBuffer
let b1 = '123'
console.log(Buffer.isBuffer(b1))

Encapsulación del método de división de búfer


ArrayBuffer.prototype.split = function (sep) {
    
    
  let len = Buffer.from(sep).length
  let ret = []
  let start = 0
  let offset = 0

  while( offset = this.indexOf(sep, start) !== -1) {
    
    
    ret.push(this.slice(start, offset))
    start = offset + len
  }
  ret.push(this.slice(start))
  return ret
}

let buf = 'zce吃馒头,吃面条,我吃所有吃'
let bufArr = buf.split('吃')
console.log(bufArr) // [ 'zce', '馒头,', '面条,我', '所有', '' ]

3. API de operación de archivos

const fs = require('fs')
const path = require('path')

// readFile 
/* fs.readFile(path.resolve('data1.txt'), 'utf-8', (err, data) => {
  console.log(err) 
  if (!null) {
    console.log(data)
  }
}) */

// writeFile 
/* fs.writeFile('data.txt', '123', {
  mode: 438,
  flag: 'w+',
  encoding: 'utf-8'
}, (err) => {
  if (!err) {
    fs.readFile('data.txt', 'utf-8', (err, data) => {
      console.log(data)
    })
  }
}) */

// appendFile
/* fs.appendFile('data.txt', 'hello node.js',{},  (err) => {
  console.log('写入成功')
}) */

// copyFile
/* fs.copyFile('data.txt', 'test.txt', () => {
  console.log('拷贝成功')
}) */

// watchFile
fs.watchFile('data.txt', {
    
    interval: 20}, (curr, prev) => {
    
    
  if (curr.mtime !== prev.mtime) {
    
    
    console.log('文件被修改了')
    fs.unwatchFile('data.txt')
  }
})

4. Realización de la conversión de md a html

md-a-html.js

const fs = require('fs')
const path = require('path')
const marked = require('marked')
const browserSync = require('browser-sync')

/**
 * 01 读取 md 和 css 内容
 * 02 将上述读取出来的内容替换占位符,生成一个最终需要展的 Html 字符串 
 * 03 将上述的 Html 字符写入到指定的 Html 文件中
 * 04 监听 md 文档内容的变经,然后更新 html 内容 
 * 05 使用 browser-sync 来实时显示 Html 内容
 */

let mdPath = path.join(__dirname, process.argv[2])
let cssPath = path.resolve('github.css')
let htmlPath = mdPath.replace(path.extname(mdPath), '.html')

fs.watchFile(mdPath, (curr, prev) => {
    
    
  if (curr.mtime !== prev.mtime) {
    
    
    fs.readFile(mdPath, 'utf-8', (err, data) => {
    
    
      // 将 md--》html
      let htmlStr = marked(data)
      fs.readFile(cssPath, 'utf-8', (err, data) => {
    
    
        let retHtml = temp.replace('{
    
    {content}}', htmlStr).replace('{
    
    {style}}', data)
        // 将上述的内容写入到指定的 html 文件中,用于在浏览器里进行展示
        fs.writeFile(htmlPath, retHtml, (err) => {
    
    
          console.log('html 生成成功了')
        })
      })
    })
  }
})

browserSync.init({
    
    
  browser: '',
  server: __dirname,
  watch: true,
  index: path.basename(htmlPath)
})

const temp = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .markdown-body {
                box-sizing: border-box;
                min-width: 200px;
                max-width: 1000px;
                margin: 0 auto;
                padding: 45px;
            }
            @media (max-width: 750px) {
                .markdown-body {
                    padding: 15px;
                }
            }
            {
     
     {style}}
        </style>
    </head>
    <body>
        <div class="markdown-body">
            {
     
     {content}}
        </div>
    </body>
    </html>
`

5. Apertura y cierre de expedientes

const fs = require('fs')
const path = require('path')

// open 
/* fs.open(path.resolve('data.txt'), 'r', (err, fd) => {
  console.log(fd)
}) */

// close
fs.open('data.txt', 'r', (err, fd) => {
    
    
  console.log(fd)
  fs.close(fd, err => {
    
    
    console.log('关闭成功')
  })
})

6. Operaciones de lectura y escritura de archivos grandes

inserte la descripción de la imagen aquí

const fs = require('fs')

// read : 所谓的读操作就是将数据从磁盘文件中写入到 buffer 中
let buf = Buffer.alloc(10)

/**
 * fd 定位当前被打开的文件 
 * buf 用于表示当前缓冲区
 * offset 表示当前从 buf 的哪个位置开始执行写入
 * length 表示当前次写入的长度
 * position 表示当前从文件的哪个位置开始读取
 */
/* fs.open('data.txt', 'r', (err, rfd) => {
  console.log(rfd)
  fs.read(rfd, buf, 1, 4, 3, (err, readBytes, data) => {
    console.log(readBytes)
    console.log(data)
    console.log(data.toString())
  })
}) */

// write 将缓冲区里的内容写入到磁盘文件中
buf = Buffer.from('1234567890')
fs.open('b.txt', 'w', (err, wfd) => {
    
    
  fs.write(wfd, buf, 2, 4, 0, (err, written, buffer) => {
    
    
    console.log(written, '----')
    fs.close(wfd)
  })
})

Siete, implementación personalizada de copia de archivos grandes

const fs = require('fs')

/**
 * 01 打开 a 文件,利用 read 将数据保存到 buffer 暂存起来
 * 02 打开 b 文件,利用 write 将 buffer 中数据写入到 b 文件中
 */
let buf = Buffer.alloc(10)

// 01 打开指定的文件
/* fs.open('a.txt', 'r', (err, rfd) => {
  // 03 打开 b 文件,用于执行数据写入操作
  fs.open('b.txt', 'w', (err, wfd) => {
    // 02 从打开的文件中读取数据
    fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
      // 04 将 buffer 中的数据写入到 b.txt 当中
      fs.write(wfd, buf, 0, 10, 0, (err, written) => {
        console.log('写入成功')
      })
    })
  })
}) */

// 02 数据的完全拷贝
/* fs.open('a.txt', 'r', (err, rfd) => {
  fs.open('b.txt', 'a+', (err, wfd) => {
    fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
      fs.write(wfd, buf, 0, 10, 0, (err, written) => {
        fs.read(rfd, buf, 0, 5, 10, (err, readBytes) => {
          fs.write(wfd, buf, 0, 5, 10, (err, written) => {
            console.log('写入成功')
          })
        })
      })
    })
  })
}) */

const BUFFER_SIZE = buf.length
let readOffset = 0

fs.open('a.txt', 'r', (err, rfd) => {
    
    
  fs.open('b.txt', 'w', (err, wfd) => {
    
    
    function next () {
    
    
      fs.read(rfd, buf, 0, BUFFER_SIZE, readOffset, (err, readBytes) => {
    
    
        if (!readBytes) {
    
    
          // 如果条件成立,说明内容已经读取完毕
          fs.close(rfd, ()=> {
    
    })
          fs.close(wfd, ()=> {
    
    })
          console.log('拷贝完成')
          return
        }
        readOffset += readBytes
        fs.write(wfd, buf, 0, readBytes, (err, written) => {
    
    
          next()
        })
      })
    }
    next()
  })
})

8. API de operación de directorio

const fs = require('fs')

// 一、access 
/* fs.access('a.txt', (err) => {
  if (err) {
    console.log(err)
  } else {
    console.log('有操作权限')
  }
}) */

// 二、stat 
/* fs.stat('a.txt', (err, statObj) => {
  console.log(statObj.size)
  console.log(statObj.isFile()) // 是不是文件
  console.log(statObj.isDirectory()) // 是不是目录
}) */

// 三、mkdir 
/* fs.mkdir('a/b/c', {recursive: true}, (err) => {
  if (!err) {
    console.log('创建成功')
  }else{
    console.log(err)
  }
}) */

// 四、rmdir
fs.rmdir('a', {
    
    recursive: true}, (err) => {
    
     // 删除目录
  if (!err) {
    
    
    console.log('删除成功')
  } else {
    
    
    console.log(err)
  }
})

// 五、readdir 
/* fs.readdir('a/b', (err, files) => {
  console.log(files)
}) */

// 六、unlink
/* fs.unlink('a/a.txt', (err) => { // 删除文件
  if (!err) {
    console.log('删除成功')
  }
}) */

Nueve, especificación commonJs

  • Cualquier archivo es un módulo con alcance independiente
  • Importar otros módulos usando require
  • Pase la identificación del módulo para requerir ubicar el módulo de destino

atributo del módulo

  • Cualquier archivo js es un módulo, puede usar el atributo del módulo directamente
  • id: devuelve el identificador del módulo, generalmente una ruta absoluta
  • nombre de archivo: devuelve la ruta absoluta del módulo de archivo
  • cargado: devuelve un valor booleano que indica si el módulo está completamente cargado
  • padre: devuelve el objeto para almacenar el módulo llamando al módulo actual
  • niños: devuelve una matriz, almacenando otros módulos llamados por el módulo actual
  • exportaciones: devuelve el contenido que el módulo actual necesita exponer
  • rutas: devuelve una matriz, almacenando la ubicación de node_modules en diferentes directorios

La diferencia entre module.exports y exportaciones

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

10. Uso del módulo VM

módulo incorporado

Cree un entorno de sandbox que se ejecute de forma independiente

const fs = require('fs')
const vm = require('vm')

let age = 33
let content = fs.readFileSync('test.txt', 'utf-8')

// eval
// eval(content) // 可以运行代码

// new Function
/* console.log(age)
let fn = new Function('age', "return age + 1") // 可以运行,但逻辑复杂
console.log(fn(age)) */

vm.runInThisContext(content) // 互相隔离

console.log(age)

11. Módulo de eventos

const EventEmitter = require('events')

const ev = new EventEmitter()

// on 
/* ev.on('事件1', () => {
  console.log('事件1执行了---2')
})

ev.on('事件1', () => {
  console.log('事件1执行了')
})

// emit
ev.emit('事件1')
ev.emit('事件1') */

// once 
/* ev.once('事件1', () => {
  console.log('事件1执行了')
})
ev.once('事件1', () => {
  console.log('事件1执行了--2')
})

ev.emit('事件1')
ev.emit('事件1') */

// off
/* let cbFn = (...args) => {
  console.log(args)
}
ev.on('事件1', cbFn) */

/* ev.emit('事件1')
ev.off('事件1', cbFn) */
// ev.emit('事件1', 1, 2, 3)

/* ev.on('事件1', function () {
  console.log(this)
})
ev.on('事件1', function () {
  console.log(2222)
})

ev.on('事件2', function () {
  console.log(333)
})

ev.emit('事件1') */

const fs = require('fs')

const crt = fs.createReadStream()
crt.on('data')

12. Publica y suscríbete

class PubSub{
    
    
  constructor() {
    
    
    this._events = {
    
    }
  }

  // 注册
  subscribe(event, callback) {
    
    
    if (this._events[event]) {
    
    
      // 如果当前 event 存在,所以我们只需要往后添加当前次监听操作
      this._events[event].push(callback)
    } else {
    
    
      // 之前没有订阅过此事件
      this._events[event] = [callback]
    }
  }

  // 发布
  publish(event, ...args) {
    
    
    const items = this._events[event]
    if (items && items.length) {
    
    
      items.forEach(function (callback) {
    
    
        callback.call(this, ...args)
      })
    }
  }
}

let ps = new PubSub()
ps.subscribe('事件1', () => {
    
    
  console.log('事件1执行了')
})
ps.subscribe('事件1', () => {
    
    
  console.log('事件1执行了---2')
})

ps.publish('事件1')
ps.publish('事件1')

Trece, mecanismo de bucle de eventos de nodejs

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
**Nota: **nextTick tiene mayor prioridad que la promesa

inserte la descripción de la imagen aquí
Prioridad de microtarea

  • En el bucle de eventos del navegador, las microtareas se almacenan en la cola de eventos, primero en entrar, primero en salir
  • process.nextTick precede a promise.then en Nodejs

14. Preguntas frecuentes sobre el anillo de eventos de nodejs

Después de múltiples ejecuciones rápidas, a veces ocurren los siguientes problemas

// 复现
setTimeout(() => {
    
    
  console.log('timeout')
}, 0)

setImmediate(() => {
    
    
  console.log('immdieate')
})

inserte la descripción de la imagen aquí


const fs = require('fs')

fs.readFile('./eventEmitter.js', () => {
    
    
  setTimeout(() => {
    
    
    console.log('timeout')
  }, 0)
  
  setImmediate(() => {
    
    
    console.log('immdieate')
  })
})

inserte la descripción de la imagen aquí
esto sera normal

15. Flujo del módulo central

Si leemos una película de G,
habrá los siguientes problemas

inserte la descripción de la imagen aquí
El uso de operaciones de flujo tiene las siguientes ventajas
inserte la descripción de la imagen aquí

Clasificación de streams en nodejs

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Dieciséis, transmisión legible personalizada

const {
    
    Readable} = require('stream')

// 模拟底层数据
let source = ['lg', 'zce', 'syy']

// 自定义类继承 Readable
class MyReadable extends Readable{
    
    
  constructor(source) {
    
    
    super()
    this.source = source
  }
  _read() {
    
    
    let data = this.source.shift() || null 
    this.push(data)
  }
}

// 实例化
let myReadable = new MyReadable(source)

/* myReadable.on('readable', () => {
  let data = null 
  while((data = myReadable.read(2)) != null) {
    console.log(data.toString())
  }
}) */

myReadable.on('data', (chunk) => {
    
    
  console.log(chunk.toString())
})

Diecisiete, flujo de escritura personalizado

const {
    
    Writable} = require('stream')

class MyWriteable extends Writable{
    
    
  constructor() {
    
    
    super()
  }
  _write(chunk, en, done) {
    
    
    process.stdout.write(chunk.toString() + '<----')
    process.nextTick(done)
  }
}

let myWriteable = new MyWriteable()

myWriteable.write('11教育', 'utf-8', () => {
    
    
  console.log('end')
})

18. Dúplex y flujo de conversión de flujo

Duplex es un flujo dúplex, es decir, puede producir un consumo de energía superior

stream-dúplex.js

let {
    
    Duplex} = require('stream')

class MyDuplex extends Duplex{
    
    
  constructor(source) {
    
    
    super()
    this.source = source
  }
  _read() {
    
    
    let data = this.source.shift() || null 
    this.push(data)
  }
  _write(chunk, en, next) {
    
    
    process.stdout.write(chunk)
    process.nextTick(next)
  }
}

let source = ['a', 'b', 'c']
let myDuplex = new MyDuplex(source)

/* myDuplex.on('data', (chunk) => {
  console.log(chunk.toString())
}) */
myDuplex.write('11教育', () => {
    
    
  console.log(1111)
})

stream-transform.js

let {
    
    Duplex} = require('stream')

class MyDuplex extends Duplex{
    
    
  constructor(source) {
    
    
    super()
    this.source = source
  }
  _read() {
    
    
    let data = this.source.shift() || null 
    this.push(data)
  }
  _write(chunk, en, next) {
    
    
    process.stdout.write(chunk)
    process.nextTick(next)
  }
}

let source = ['a', 'b', 'c']
let myDuplex = new MyDuplex(source)

/* myDuplex.on('data', (chunk) => {
  console.log(chunk.toString())
}) */
myDuplex.write('11', () => {
    
    
  console.log(1111)
})

19. Eventos y aplicaciones de transmisión legibles por archivo

const fs = require('fs')

let rs = fs.createReadStream('test.txt', {
    
    
  flags: 'r',
  encoding: null, 
  fd: null,
  mode: 438,
  autoClose: true, 
  start: 0,
  // end: 3,
  highWaterMark: 4
})

/* rs.on('data', (chunk) => {
  console.log(chunk.toString())
  rs.pause()
  setTimeout(() => {
    rs.resume()
  }, 1000)
}) */

/* rs.on('readable', () => {
  let data = rs.read()
  console.log(data)
  let data
  while((data = rs.read(1)) !== null) {
    console.log(data.toString())
    console.log('----------', rs._readableState.length)
  }
}) */

rs.on('open', (fd) => {
    
    
  console.log(fd, '文件打开了')
})

rs.on('close', () => {
    
    
  console.log('文件关闭了')
})
let bufferArr = []
rs.on('data', (chunk) => {
    
    
  bufferArr.push(chunk)
})

rs.on('end', () => {
    
    
  console.log(Buffer.concat(bufferArr).toString())
  console.log('当数据被清空之后')
})

rs.on('error', (err) => {
    
    
  console.log('出错了')
})

20. Flujo de archivos grabable

const fs = require('fs')

const ws = fs.createWriteStream('test.txt', {
    
    
  flags: 'w', 
  mode: 438,
  fd: null,
  encoding: "utf-8",
  start: 0,
  highWaterMark: 3
})

let buf = Buffer.from('abc')

// 字符串 或者  buffer ===》 fs rs
/* ws.write(buf, () => {
  console.log('ok2')
}) */

/* ws.write('11', () => {
  console.log('ok1')
}) */

/* ws.on('open', (fd) => {
  console.log('open', fd)
}) */

ws.write("2")

// close 是在数据写入操作全部完成之后再执行
/* ws.on('close', () => {
  console.log('文件关闭了')
}) */

// end 执行之后就意味着数据写入操作完成
ws.end('11')


// error
ws.on('error', (err) => {
    
    
  console.log('出错了')
})


Veintiuno, proceso de ejecución de escritura

const fs = require('fs')

let ws = fs.createWriteStream('test.txt', {
    
    
  highWaterMark: 3
})

let flag = ws.write('1')
console.log(flag)

flag = ws.write('2')
console.log(flag)

// 如果 flag 为 false 并不是说明当前数据不能被执行写入
// 

ws.on('drain', () => {
    
    
  console.log('11')
})
  1. La primera vez que se llama al método de escritura, los datos se escriben directamente en el archivo
  2. El segundo inicio del método de escritura es escribir los datos en el caché.
  3. La velocidad de producción es diferente de la velocidad de consumo.Generalmente, la velocidad de producción es mucho más rápida que la velocidad de consumo.
  4. Cuando la bandera es falsa, no significa que los datos actuales no se puedan escribir, pero debemos informar al productor de datos que la velocidad de consumo actual ya no puede seguir el ritmo de la velocidad de producción, por lo que en este momento, generalmente usamos la lectura. módulo de transmisión Cambiar al modo de pausa.
  5. Cuando el productor de datos hace una pausa, el consumidor digiere lentamente los datos en su caché interna hasta que se puedan volver a escribir.
  6. ¿Cómo informar al productor cuándo el búfer puede continuar escribiendo datos? evento de drenaje

Veintidós, controla la velocidad de escritura.

/**
 * 需求:“11” 写入指定的文件
 * 01 一次性写入
 * 02 分批写入
 * 对比:
 */
let fs = require('fs')

let ws = fs.createWriteStream('test.txt', {
    
    
  highWaterMark: 3
})

// ws.write('11')
let source = "11".split('')
let num = 0
let flag = true

function executeWrite () {
    
    
  flag = true
  while(num !== 4 && flag) {
    
    
    flag = ws.write(source[num])
    num++
  }
}

executeWrite()

ws.on('drain', () => {
    
    
  console.log('drain 执行了')
  executeWrite()
})

// pipe

23. Mecanismo de contrapresión

El flujo de node.js ha implementado el mecanismo de contrapresión.

inserte la descripción de la imagen aquí
Desbordamiento de memoria, llamadas frecuentes de GC, otros procesos se ralentizan

inserte la descripción de la imagen aquí

let fs = require('fs')

let rs = fs.createReadStream('test.txt', {
    
    
  highWaterMark: 4
})

let ws = fs.createWriteStream('test1.txt', {
    
    
  highWaterMark: 1
})

let flag = true

/* rs.on('data', (chunk) => {
  flag = ws.write(chunk, () => {
    console.log('写完了')
  })
  if (!flag) {
    rs.pause()
  }
})

ws.on('drain', () => {
  rs.resume()
}) */

rs.pipe(ws)

Veinticuatro, estructura de lista enlazada

¿Por qué no usar arreglos para almacenar datos?

Desventajas de la matriz

  • La longitud de los datos almacenados en la matriz tiene un límite superior
  • La matriz tiene un problema de colapso.

inserte la descripción de la imagen aquí

25. Uso del método de tubería

const fs = require('fs')
const myReadStream = require('./ReadStream')

// const rs = fs.createReadStream('./f9.txt', {
    
    
//   highWaterMark: 4
// })

const rs = new myReadStream('./f9.txt')

const ws = fs.createWriteStream('./f10.txt')

rs.pipe(ws)

// data 

Je suppose que tu aimes

Origine blog.csdn.net/woyebuzhidao321/article/details/126295044
conseillé
Classement