Node 核心编程 -- 核心模块一

12 篇文章 1 订阅
本文深入探讨了Node.js的核心模块,包括process模块的内存和CPU使用情况,运行环境信息,以及进程状态。同时,详细阐述了Buffer的使用,如创建、填充、读写和转换数据。接着,介绍了FS模块的各种文件和目录操作,如读写、拷贝、监控和权限检查。此外,还涉及了模块化机制,特别是CommonJS规范和VM模块。整个内容旨在帮助开发者更好地理解和运用Node.js进行系统级编程。
摘要由CSDN通过智能技术生成

process

  1. 资源: cpu 内存

    console.log(process.memoryUsage())
    console.log(process.cpuUsage())
    
  2. 运行环境:运行目录、node环境、cpu架构、用户环境、系统平台

    console.log(process.cwd())
    console.log(process.version)
    console.log(process.versions)
    console.log(process.arch)
    console.log(process.env.NODE_ENV)
    console.log(process.env.PATH)
    console.log(process.env.USERPROFILE)  // HOME
    console.log(process.platform)
    
  3. 运行状态: 启动参数、PID、运行时间

    console.log(process.argv)
    console.log(process.argv0)  // execArgv
    console.log(process.pid)   // ppid 
    
    setTimeout(() => {
      console.log(process.uptime())
    }, 3000)
    
  4. 事件

    process.on('beforeExit', code => {
      console.log('before exit' + code)
    })
    
    // 函数内部不支持异步
    process.on('exit', (code) => {
      console.log('exit' + code)
      setTimeout(() => {
        console.log(123)
      },1000)
    })
    
    // 主动退出
    process.exit()
    
    console.log('代码执行完了')
    
  5. 标准输出 输入 错误

    console.log = function (data) {
      process.stdout.write('---' + data + '\n')
    }
    
    console.log(11)
    console.log(22)
    
    const fs = require('fs')
    fs.createReadStream('test.text')
      .pipe(process.stdout)
    
    process.stdin.pipe(process.stdout)
    
    process.stdin.setEncoding('utf-8')
    process.stdin.on('readable', () => {
      let chunk = process.stdin.read()
      if(chunk !== null){
        process.stdout.write('data' + chunk)
      }
    })
    

path

const path = require('path')
  • 获取路径中的基础名称

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

    /**
     * 01 返回路径中最后一个部分的上一层目录所在路径
     */
    console.log(path.dirname(__filename))
    console.log(path.dirname('/a/b/c'))
    console.log(path.dirname('/a/b/c/'))
    
  • 获取路径的扩展名

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

    /**
     * 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)
    
  • 序列化路径

    const obj = path.parse('./a/b/c/')
    console.log(path.format(obj))
    
  • 判断当前路径是否为绝对

    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'))
    
  • 拼接路径

    console.log(path.join('a/b', 'c', 'index.html'))
    console.log(path.join('/a/b', 'c', 'index.html'))
    console.log(path.join('/a/b', 'c', '../', 'index.html'))
    console.log(path.join('/a/b', 'c', './', 'index.html'))
    console.log(path.join('/a/b', 'c', '', 'index.html'))
    console.log(path.join(''))
    
  • 规范化路径

    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'))
    
  • 绝对路径

    console.log(path.resolve())
    /**
     * resolve([from], to)
     */
    console.log(path.resolve('/a', '../b'))
    console.log(path.resolve('index.html'))
    

Buffer

  • 无需 require 的一个全局变量
  • 实现 Node 平台下的二进制数据操作
  • 不占据 V8 堆内存大小的内存空间
  • 内存的使用由 Node 来控制,由 V8 的 GC 回收
  • 一般配合 Stream 流使用,充当数据缓冲区

在这里插入图片描述
创建 Buffer 实例

  • alloc:创建指定大小的 Buffer
  • allocUnsafe:创建指定大小的 Buffer (不安全)
  • from:接收数据,创建 Buffer

Buffer 实例方法

  • fill:使用数据填充 Buffer

    buf.fill(123)
    console.log(buf)
    console.log(buf.toString())
    
  • write:向 Buffer 中写入数据

    buf.write('123', 1, 4)
    console.log(buf)
    console.log(buf.toString())
    
  • toString:从 Buffer 中提取数据

    buf = Buffer.from('拉勾教育')
    console.log(buf)
    console.log(buf.toString('utf-8', 3, 9))
    
  • slice:截取 Buffer

    buf = Buffer.from('拉勾教育')
    let b1 = buf.slice(-3)
    console.log(b1)
    console.log(b1.toString())
    
  • indexOf:在 Buffer 中查找数据

    buf = Buffer.from('zce爱前端,爱拉勾教育,爱大家,我爱所有')
    console.log(buf)
    console.log(buf.indexOf('爱qc', 4))
    
  • copy:拷贝 Buffer 中的数据

    let b1 = Buffer.alloc(6)
    let b2 = Buffer.from('拉勾')
    
    b2.copy(b1, 3, 3, 6)
    console.log(b1.toString())
    console.log(b2.toString())
    

Buffer 静态方法

  • concat:将多个 Buffer 拼接成一个新的 Buffer

    let b1 = Buffer.from('拉勾')
    let b2 = Buffer.from('教育')
    
    let b = Buffer.concat([b1, b2], 9)
    console.log(b)
    console.log(b.toString())
    
  • isBuffer:判断当前数据是否为 Buffer

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

自定义 Buffer 之 split

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)

FS 模块

在这里插入图片描述在这里插入图片描述
常见 flag 操作符

  • r:表示可读
  • w:表示可写
  • s:表示同步
  • +:表示执行相反操作
  • x:表示排他操作
  • a:表示追加操作

fs 介绍总结

  • fs 是 Node 中内置的核心模块
  • 代码层面上 fs 分为基本操作类和常用 API
  • 权限位、标识符、操作符

文件操作 API

  • 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')
      }
    })
    

文件操作实现 md 转 html

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>
`

文件打开与关闭

  • 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('关闭成功')
      })
    })
    

大文件读写操作

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)
  })
})

文件拷贝自定义实现

const fs = require('fs')
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()
  })
})

FS 之目录操作 API(常见目录操作 API)

  • 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('删除成功')
      }
    })
    

模块化

常见模块化规范

  • Commonjs 规范
  • AMD 规范
  • CMD 规范
  • ES modules 规范

Nodejs 与 Commonjs

  • 任意一个文件就是一个模块,具有独立作用域
  • 使用 require 导入其他模块
  • 将模块 ID 传入 require 实现目标模块定位

module 属性

  • 任意 js 文件就是一个模块,可以直接使用 module 属性
  • id:返回模块标识符,一般是一个绝对路径
  • filename:返回文件模块的绝对路径
  • loaded:返回布尔值,表示模块是否加载完成
  • parent:返回对象存放调用当前模块的模块
  • children:返回数组,存放当前模块调用的其他模块
  • exports:返回当前模块需要暴露的内容
  • paths:返回数组,存放不同目录下的 node_modules 位置

require 属性

  • 基本功能是读入并执行一个模块文件
  • resolve:返回模块文件绝对路径
  • extensions:依据不同后缀名执行解析操作
  • main:返回主模块对象

CommonJS 规范

  • CommonJS 规范起初是为了弥补 js 语言模块化缺陷
  • CommonJS 是语言层面的规范,当前主要用于 node.js
  • CommonJS 规定模块化分为引入、定义、标识符三个部分
  • Module 在任意模块中可直接使用包含模块信息
  • Require 接收标识符,加载目标模块
  • Exports 和 module.exports 都能导出模块数据
  • CommonJS 规范定义模块的加载是同步完成

内置模块之 VM

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("age += 10")

console.log(age)

模块加载模拟实现

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

function Module (id) {
  this.id = id
  this.exports = {}
  console.log(1111)
}

Module._resolveFilename = function (filename) {
  // 利用 Path 将 filename 转为绝对路径
  let absPath = path.resolve(__dirname, filename)
  
  // 判断当前路径对应的内容是否存在()
  if (fs.existsSync(absPath)) {
    // 如果条件成立则说明 absPath 对应的内容是存在的
    return absPath
  } else {
    // 文件定位
    let suffix = Object.keys(Module._extensions)

    for(var i=0; i<suffix.length; i++) {
      let newPath = absPath + suffix[i]
      if (fs.existsSync(newPath)) {
        return newPath
      }
    }
  }
  throw new Error(`${filename} is not exists`)
}

Module._extensions = {
  '.js'(module) {
    // 读取
    let content = fs.readFileSync(module.id, 'utf-8')

    // 包装
    content = Module.wrapper[0] + content + Module.wrapper[1] 
    
    // VM 
    let compileFn = vm.runInThisContext(content)

    // 准备参数的值
    let exports = module.exports
    let dirname = path.dirname(module.id)
    let filename = module.id

    // 调用
    compileFn.call(exports, exports, myRequire, module, filename, dirname)
  },
  '.json'(module) {
    let content = JSON.parse(fs.readFileSync(module.id, 'utf-8'))

    module.exports = content
  }
}

Module.wrapper = [
  "(function (exports, require, module, __filename, __dirname) {",
  "})"
]

Module._cache = {}

Module.prototype.load = function () {
  let extname = path.extname(this.id)
  
  Module._extensions[extname](this)
}

function myRequire (filename) {
  // 1 绝对路径
  let mPath = Module._resolveFilename(filename)
  
  // 2 缓存优先
  let cacheModule = Module._cache[mPath]
  if (cacheModule) return cacheModule.exports

  // 3 创建空对象加载目标模块
  let module = new Module(mPath)

  // 4 缓存已加载过的模块
  Module._cache[mPath] = module

  // 5 执行加载(编译执行)
  module.load()

  // 6 返回数据
  return module.exports
}

let obj = myRequire('./v')
let obj2 = myRequire('./v')
console.log(obj.age)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值