process
-
资源: cpu 内存
console.log(process.memoryUsage()) console.log(process.cpuUsage())
-
运行环境:运行目录、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)
-
运行状态: 启动参数、PID、运行时间
console.log(process.argv) console.log(process.argv0) // execArgv console.log(process.pid) // ppid setTimeout(() => { console.log(process.uptime()) }, 3000)
-
事件
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('代码执行完了')
-
标准输出 输入 错误
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)