【Node基础】

一、简介

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。
Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使得 Node.js 的性能非常好。

二、命令行运行

node app.js

三、模块

Node提供了一个简单的模块系统让Nodejs的文件可以相互调用。模块加载采用的是同步加载的commonjs规范
commonjs:

  • 每个文件都是封装的一个模块,模块里定义的变量、函数、类都是私有的
  • module代表当前模块、默读了是封闭,但它的exports属性向外提供调用接口
  • require 加载模块,读取并执行一个js文件,然后返回该模块的exports对象
  • commonjs是同步加载的,因此模块加载的顺序严格按照代码执行顺序
  • 模块可以多次加载,但是第一次加载之后模块会被编译执行,放入缓存,后续的require直接从缓存里取值,模块代码不在编译执行

require内部处理流程

  • 检查Module._cache 是否缓存了置顶模块
  • 如果缓存没有的话,就创建一个新的默读了实例将它保存到缓存
  • module.load()加载指定模块
  • 在解析的过程中如果发生异常,九从缓存中删除该模块
  • 返回该模块的module.exports

模块化导入方式

  • global.address = ‘zhengzhou’ // 全局变量
  • module.exports = ‘str’
  • module.exports.msg = ‘str’
  • exports.msg = ‘str’ //  module.exports.msg 简写
  • exports = ‘str’ // 错误

四、HTTP

Node内置模块HTTP可以用来创建HTTP服务器
要使用HTTP服务器和客户端,则必须require(‘http’)

const http = require('http')
const port = 3000
const server = http.createServer((req, res) => {
	res.statusCode = 200
	res.setHeader('Content-type', 'text/plain; charset=utf8')
	res.end('hi--alhuo')
})
server.listen(port, () => {
	console.log('服务器启动了')
})

1. http.server
通过http.createServer或者new http.Server() 可以创建一个http.server实例

  • close() 暂停服务
  • listen 启动服务器监听

2.request响应体

  • write
    向前端返回数据,该方法可调用多次,返回的数据会被凭借到一起
  • end
    接收请求,同时response.end 方法也可以用来向前端返回数据
  • setHeader
    设置响应头,如果该头信息已存在,则覆盖
  • statusCode
    设置响应状态
  • statusMessage
    设置响应状态信息

3.请求方式

  • request
  • get
    两种请求都接受以下参数
    • url 请求地址
    • options请求配置
    • callback 请求成功回调

options请求配置包括

  • host:表示请求网站的域名或者IP地址,默认为localhost
  • hostname:服务器域名,主机名是首选的值
  • port:请求网站的端口,默认为80
  • method:HTTP请求方法,默认是GET(http.get时值只有GET)
  • path:请求的相对根的路径,默认是/ QueryString应该包含在其中,例如:/index.html?page=1
  • headers:请求头对象

五、fs

在Nodejs中,所有与文件操作都是通过fs核心模块来实现的,包括文件目录的创建,删除,查询以及文件的读取和写入,在fs模块中,所有的方法都分为同步和异步两种实现。带sync的为同步。

1.文件读取

const fs = require('fs')
// 同步读取
let buf = fs.readFileSync('demo.txt')
let data = fs.readFileSync('demo.txt', 'utf8')
console.log(buf) // <Buffer 48 65 6c 6c 6f>
console.log(data) // Hello

// 异步读取
fs.readFile('demo.txt', 'utf8', (err, data) => {
	console.log(err) // null
	console.log(data) // Hello
})

2.文件写入

const fs = require('fs')
// 同步写入
fs.writeFileSync('demo.txt', "hello world")
let data = fs.readFileSync('demo.txt', 'utf8')
console.log(data) // hello world 
// 异步写入
fs.writeFile('demo.txt', 'hello world', err => {
	if (!err) {
		fs.readFile('demo.txt', 'utf8', (err, data) => {
			console.log(data) // hello world
		})
	}
})

3.追加写入

const fs = require('fs')
// 同步追加
fs.appendFileSync('demo.txt', "world")
let data = fs.readFileSync('demo.txt', 'utf8')
console.log(data) // hello world 
// 异步追加
fs.appendFile('demo.txt', 'world', err => {
	if (!err) {
		fs.readFile('demo.txt', 'utf8', (err, data) => {
			console.log(data) // hello world
		})
	}
})

4.文件拷贝写入

const fs = require('fs')
// 同步拷贝
fs.copyFileSync('demo.txt', "newdemo.txt")
let data = fs.readFileSync('newdemo.txt', 'utf8')
console.log(data) // hello world 
// 异步拷贝
fs.copyFile('demo.txt', 'newdemo.txt', err => {
	if (!err) {
		fs.readFile('newdemo.txt', 'utf8', () => {
			console.log(data) // hello world
		})
	}
})

5.创建目录

const fs = require('fs')
// 同步创建文件目录a/b
fs.mkdirSync("a/b")
// 在b目录下创建c.text,其实创建的还是一个目录
fs.mkdirSync("a/b/c.text")
// 异步创建目录
fs.mkdir('a/b/c', err => {
	if (!err) {
		console.log('创建成功')
	}
})

6.创建文件

const fs = require('fs')
// 同步 a目录下创建demo.txt
fs.writeFileSync('a/demo.txt', "hello world")
// 异步同理
...

7.读取文件目录

const fs = require('fs')
// 同步读取目录
let data = fs.readdirSync('a/b')
console.log(data) // ['c', 'index.js']
// 异步读取目录
fs.readdir('a/b', , (err,data) => {
	if (!err) {
		console.log(data) // ['c', 'index.js']
	}
})

8.删除文件目录

const fs = require('fs')
// 同步删除
let data = fs.rmdirSync('a/b')
// 异步删除
fs.readdir('a/b', , (err,data) => {
	if (!err) {
	}
})

9.删除文件

const fs = require('fs')
// 同步删除
let data = fs.unlinkSync('a/index.js')
// 异步删除
fs.unlink('a/index.js', , (err,data) => {
	if (!err) {
	}
})

fs常用方法

  • fs.access() 检查文件是否存在,以及nodejs是否有权限访问
  • fs.appendFile() 最近数据到文件,如果文件不存在,则创建文件
  • fs.chmod() 更改文件的权限,相关方法(fs.lchmod, fs.fchmod)
  • fs.chown() 更改文件的所有者和群组,相关方法(fs.lchown, fs.fchown)
  • fs.close 关闭文件描述符
  • fs.copyFile() 拷贝文件
  • fs.createReadStream() 创建可读的文件流
  • fs.createWriteStream() 创建可写的文件流
  • fs.link() 新增指向文件的硬链接
  • fs.mkdir 新建文件夹
  • fs.mkdtemp 创建临时目录
  • fs.open() 设置文件模式
  • fs.readdir() 读取目录内容
  • fs.readFile() 读取文件内容,相关方法:fs.read()
  • fs.readlink() 读取符号链接的值
  • fs.realpath() 将相对的文件路径指针解析为完整的路径
  • fs.rename() 重命名文件或文件夹
  • fs.rmdir() 删除文件夹
  • fs.stat() 返回文件的状态,相关方法(fs.lstat, fs.fstat)
  • fs.symlink() 新建文件的符号链接
  • fs.truncate() 将传递的文件名标识的文件截断为指定的长度,相关方法fs.ftruncate()
  • fs.unlink() 删除文件或符号链接
  • fs.unwatchFile() 停止监听文件上的更改
  • fs.utime() 改改文件的时间戳
  • fs.watchFile() 监听文件更改
  • fs.writeFile() 写入文件

六、path

path模块提供了许多函数来访问文件系统并与文件系统进行交互
1. path.basename()
返回路径的最后一部分,第二个参数可以过滤掉文件的扩展名

require('path').basename('/test/something') // something
require('path').basename('/test/something.txt') // something.txt
require('path').basename('/test/something', '.txt') // something

2. path.dirname()
返回路径的目录部分

require('path').dirname('/test/something') // test
require('path').dirname('/test/something/file.txt') // /test/something

3. path.extname()
返回路径的扩展名部分

require('path').extname('/test/something') // ''
require('path').extname('/test/something/file.txt') // '.txt'

4. path.isAbsolute()
如果是绝对路径,则返回 true

require('path').isAbsolute('/test/something') // true
require('path').isAbsolute('./test/something') // false

5. path.join()
连接路径的两个或多个部分

const name = 'joe'
require('path').join('/', 'users', name, 'notes.txt') //'/users/joe/notes.txt'

6. path.normalize()
当包含类似 .、… 或双斜杠等相对的说明符时,则尝试计算实际的路径

require('path').normalize('/users/joe/..//test.txt') //'/users/test.txt'

7. path.parse()
解析对象的路径为组成其的片段:

  • root: 根路径。
  • dir: 从根路径开始的文件夹路径。
  • base: 文件名 + 扩展名
  • name: 文件名
  • ext: 文件扩展名
require('path').parse('/users/test.txt')
/*
{
  root: '/',
  dir: '/users',
  base: 'test.txt',
  ext: '.txt',
  name: 'test'
}
*/

8. path.relative()
接受 2 个路径作为参数。 基于当前工作目录,返回从第一个路径到第二个路径的相对路径

require('path').relative('/Users/joe', '/Users/joe/test.txt') //'test.txt'
require('path').relative('/Users/joe', '/Users/joe/something/test.txt') //'something/test.txt'

9. path.resolve()
可以使用 path.resolve() 获得相对路径的绝对路径计算

path.resolve('joe.txt') //'/Users/joe/joe.txt' 如果从主文件夹运行

通过指定第二个参数,resolve 会使用第一个参数作为第二个参数的基准:

path.resolve('tmp', 'joe.txt') //'/Users/joe/tmp/joe.txt' 如果从主文件夹运行

如果第一个参数以斜杠开头,则表示它是绝对路径:

path.resolve('/etc', 'joe.txt') //'/etc/joe.txt'

七、事件模块

events 模块为提供了 EventEmitter 类,这是在 Node.js 中处理事件的关键

const EventEmitter = require('events')
const door = new EventEmitter()

事件监听器返回及使用以下事件

  • 当监听器被添加时返回 newListener
  • 当监听器被移除时返回 removeListener

emitter.addListener()
emitter.on() 的别名

emitter.emit()
触发事件。 按照事件被注册的顺序同步地调用每个事件监听器

door.emit("slam") // 触发 "slam" 事件。

emitter.eventNames()
返回字符串(表示在当前 EventEmitter 对象上注册的事件)数组

door.eventNames()

emitter.getMaxListeners()
获取可以添加到 EventEmitter 对象的监听器的最大数量(默认为 10,但可以使用 setMaxListeners() 进行增加或减少)

door.getMaxListeners()

emitter.listenerCount()
获取作为参数传入的事件监听器的计数

door.listenerCount('open')

emitter.listeners()
获取作为参数传入的事件监听器的数组

door.listeners('open')

emitter.off()
emitter.removeListener() 的别名,新增于 Node.js 10

emitter.on()
添加当事件被触发时调用的回调函数

door.on('open', () => {
  console.log('打开')
})

emitter.once()
添加当事件在注册之后首次被触发时调用的回调函数。 该回调只会被调用一次,不会再被调用

const EventEmitter = require('events')
const ee = new EventEmitter()

ee.once('my-event', () => {
  //只调用一次回调函数。
})

emitter.prependListener()
当使用 on 或 addListener 添加监听器时,监听器会被添加到监听器队列中的最后一个,并且最后一个被调用。 使用 prependListener 则可以在其他监听器之前添加并调用。
emitter.prependOnceListener()
当使用 once 添加监听器时,监听器会被添加到监听器队列中的最后一个,并且最后一个被调用。 使用 prependOnceListener 则可以在其他监听器之前添加并调用
emitter.removeAllListeners()
移除 EventEmitter 对象的所有监听特定事件的监听器

door.removeAllListeners('open')

emitter.removeListener()
移除特定的监听器。 可以通过将回调函数保存到变量中(当添加时),以便以后可以引用它

const doSomething = () => {}
door.on('open', doSomething)
door.removeListener('open', doSomething)

emitter.setMaxListeners()
设置可以添加到 EventEmitter 对象的监听器的最大数量(默认为 10,但可以增加或减少)

door.setMaxListeners(50)

八、buffer

Buffer是内存区域。它表示在V8 JavaScript 引擎外部分配的固定大小的内存(无法调整大小)
可以将Buffer视为整数数组,每个整数代表一个数据字节
Buffer被引入用以帮助开发者处理二进制数据,在此生态系统中传统上只处理字符串而不是二进制数据。
Buffer与流紧密相连,当流处理器接受数据的速度快于其消化的速度,则会把数据放入buffer中。
一个简单的场景:当观看YouTube视频时,红线超过了观看点:即下砸数据的速度比查看数据的速度快时,切浏览器会对数据进行缓冲。

1. 创建buffer
Buffer.from() 返回新的Buffer

const Buffer = require('buffer').Buffer
// 创建包含字符串‘hello’ 的 UTF-8字节的新缓冲区
const buf = Buffer.from([0x68, 0x65, 0x6c, 0x6c 0x6f])

var str = buf.toString('utf-8') // hello,默认是utf-8

// 创建初始化 buffer(传入大小)字节
const buf = Buffer.alloc(1024, '嗨喽', 'utf-8')
// 打印出来乱码,并且不能设置编码,只有一个参数,底层不会被初始化,有旧数据不安全
const buf = Buffer.allocUnsafe(1024)

// 获取长度
console.log(buf.length)
// 遍历缓冲区
for (const i of buf) {
	console.log(i)
	编码遍历之后转字符串
	Buffer.from([i].toString()
}
// 替换buf中的内容 write,改写时buffer内存不足时,**只能填进去一部分**
cont bufstr = Buffer.from('Hey!')
bufstr.write('帅哥')

// 复制一个buffer, 必须先创建再复制
const bufstr2 = Buffer.alloc(4)
bufstr2.copy(bufstr)

// 切片 buffer
// 如果要创建 buffer 的局部视图,则可以创建切片。 切片不是副本:原始 buffer 仍然是真正的来源。 如果那改变了,则切片也会改变
const buf = Buffer.from('Hey!')
buf.slice(0).toString() //Hey!
const slice = buf.slice(0, 2)
console.log(slice.toString()) //He
buf[1] = 111 //o
console.log(slice.toString()) //Ho

九、流

流是数据的集合,就像数组或者字符串,他们之间的区别就是流可能不是一次性获取到的,他们不需要匹配内存,这让流在处理大容量数据,或者从一个额外的源每次获取一块数据的时候变大非常强大。
流的优点

  • 内存效率:无需加载大量的数据到内存中即可进行处理
  • 时间效率:当获得数据之后即可立即开始处理数据,这样所需的时间更少,而不必等到整个数据有效负载可用才开始
    NodeJs,Stream 有四种流类型:
  • Readable 可读操作
  • Writeable 可写操作
  • Duplex 可读写操作
  • Transform 操作被写入数据,然后读出结果

所有的Stream对象都是EventEmitter的实例。常用的事件有:

  • data 当有数据可读时触发
  • end 没有更多数据可读时触发
  • error 在接收和写入过程中发生错误触发
  • finish 所有数据已被写入到底层系统时触发

1.读取流
读取流包括

  • 客户端上的HTTP响应
  • 服务器上的HTTP请求
  • 文件系统读取流
  • 压缩流
  • 加密流

创建流对象

const Stream = require('stream')
// 创建读取流对象
const readableStream = new Stream.Readable()
// 实现_read方法,所有Readable实现都必须提供readable._read() 方法的实现
readableStream._read = () => {}

readableStream.push('放入0')
readableStream.on('data', (str) => {
	console.log(str.toString()) // 放入0  放入1
})
readableStream.push('放入1')

以最高效率获取文件内容

let infoStr = ''
var infoTextStream = fs.createReadStream('info.txt')
infoTextStream.setEncoding('utf8')
infoTextStream.on('open', () => {
	console.log('文件打开了')
})
infoTextStream.on('data', (str) => {
	console.log(str)
})
infoTextStream.on('error', (err) => {
	console.log(err)
})
// close 或者 end 一样
infoTextStream.on('close', () => {
	console.log('close')
})

2.写入流
写入流包括

  • 客户端上的HTTP请求
  • 服务器上的HTTP响应
  • 文件系统写入流
  • 压缩流
  • 加密流

创建写入流
若要创建可写流,需要继承基本的writable对象,并实现其_write() 方法

const Stream = require('stream')
// 创建写入流对象
const writableStream = new Stream.Writable()
writableStream._write = (chunk, encoding, next) => {
  console.log(chunk.toString())
  next()
}
writableStream.write('hello', () => {
	console.log('写入了hello')
})

写入文档流

var WriteStream = fs.createWriteStream('info.txt')
WriteStream.write('我是写入的流', 'utf8')
WriteStream.write('我是写入的流1', 'utf8')
WriteStream.end() // 写入完成
WriteStream.on('finish', () => {
})
WriteStream.on('error', (err) => {
})

3.读写流

const readableStream = new Stream.Readable({
	read () {}
})

const writableStream = new Stream.Writable({
	write(chunk, encoding, next) {
  		console.log(chunk.toString())
  		next()
	}
})
//  读取流通过管道流入写入流
readableStream.pipe(writableStream)
// 读取流中推入数据
readableStream.push('hey')
readableStream.push('hey1')

// 也可以使用 readable 事件直接地消费可读流
readableStream.on('readable', () => {
  console.log(readableStream.read())
})

node 特点

1.异步非阻塞I/O
在Node中,绝大多数的操作都以一步的方式进行调用,从文件读取到网络请求,,异步I/O意味着每个调用之间无需等待之前的I/O调用结束
2.事件回调
在Node中回调也是无处不在,事件的处理基本都是依赖回调来实现的,在JS中,可以将函数作为对象传递给方法作为实参进行调用
3.单线程
单线程的运行会导致无法利用多核CPU,一旦程序发生错误就会引起整个程序退出,并且大量的计算会占用CPU从而阻塞后续的程序运行
Node是指上就是给JS提供一个web以外的运行环境,所以我们其实也是在Node内编写JS
Node内的I/O事件是异步的,整个事件驱动过程中不会阻塞新的任务发起,理论上NodeJs能支持比Java、PHP程序更高的并发量,虽然维护事件队列也需要成本,再由于NodeJs是单线程,事件队列越长,得到的响应的时间就越长。

node 使用场景

1. I/O密集
Node异步I/O的特点可以轻松面对I/O密集型的业务场景,处理效率将比同步I/O高,虽然同步I/O可以采用多线程或者多进程的方式进行,但是相比Node自身异步I/O的特性来说,静增加对内存和CPU的开销,但是由于Node是单线程,所有如果有长时间运行的计算(比如大循环),将会导入CPU时间片不能释放,使得后面I/O无法发起
解决方案:分解大型运算任务为多个小任务,使得运算能够适当释放,不阻塞I/O调用的发起
2. 高并发
Node可以处理万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可,它本质上只是从某个数据库中查找一些值并将它们组成一个响应,由于响应市少量文本,入站请求也是少量文本,因此流量不高,可轻松应对。

参考网站:http://nodejs.cn/learn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值