nodejs 主线程是单线程(异步)
将后续的逻辑写成函数,传入到当前执行函数中,当执行到函数得到了结果后,执行传入到函数(回调函数)
web 异步
- setTimeout
- callback
- onclick
- ajax
阻塞不能异步(阻塞是针对内核)IO
操作,读写操作,异步操作(能用异步绝不用同步)event-driven
事件驱动(发布订阅:当前队列,异步队列)
模块
node
自带模块化功能,一个js文件就是模块。(闭包)
模块this
不是global
每个文件都有局部作用域,不会将属性挂在global
上。
全局变量
在所有模块中都可以使用
- console
- process 进程,设置环境变量
- Buffer 缓存区
- clearImmediate,clearInterval,clearTimeout
- setImmediate,setInterval,setTimeout
在命令行里配置NODE_ENV
:export
异步(下一个队列,在下一个队列的底部):process.nextTick()
存在于模块范围内的全局变量
- __dirname
- __filename
- require()
- exports
- module
模块化:低耦合(每个与模块之前没有关系),高内聚(相同代码,相同逻辑放在一起),方便维护,防止代码冲突(命名冲突)。
单例:不能保证一定不冲突,导致调用过长。
浏览器端的模块化:
- CMD seajs 就近依赖
- AMD requirejs 依赖前置
node
基于规范commonjs
,是基于文件的读写,node
天生自带模块化。
- 定义如何创建一个模块,一个js文件就是一个模块
- 如何使用一个模块,
require()
(具有缓存功能,多次引用,只执行一次) - 如何导出一个模块,
exports.xxx = xxx
(导出的是命名对象),module.exports = xxx
(导出什么就拿到什么)
npm
全局安装 -g
, 只能在命令行中使用,默认安装路径可以通过npm root -g
来查看。
nrm
(切换node源工具),nvm
(管理node版本工具)
不会安装到全局比变量中,而是通过npm进行映射。
nrm test // 测试连接时间
nrm ls // 显示所有的可用源
nrm use 源的名字 // 使用源
发布包
name
version
main
license
- 包名不能和已有一致
- 入口文件,做用是整合
- 注册账号,如果有账号表示登陆
npm addUser
- 发布
npm publish
util.promisify()
util.promiseify(fs.readFile) // 把一个函数promise化
buffer
buffer
存的很像数组,存储是以内存空间存储。
特点:
- 不能改变大小
- 类似数组操作方法
- buffer.fill 填充buffer中的内容
- buffer.toString 将buffer转化成字符串
- buffer.slice 截取想要的buffer
- buffer.copy 拷贝buffer
- buffer.concat buffer的拼接方法
- buffer.isBuffer 判断是否是buffer类型
slice
var buffer = Buffer.from([1, 2, 3])
var newBuffer = buffer.slice(0, 1) // 浅拷贝,存放内存地址空间
包前不包后
copy
// targetBuffer 目标buffer, targetStrat 目标的开始, sourceStart 源的开始, sourceEnd 源的结束 this.length
// Buffer.copy()
var buf1 = Buffer.from('123')
var buf2 = Buffer.from('456')
var buf = Buffer.allocUnsafe(12)
buf1.copy(buf, 0)
buf2.copy(buf, 6)
concat
Buffer.concat([buf1, buf2], newBuffer.length)
实现concat方法
Buffer._concat = (list, totalLength = 0) => {
// 判断长度是否传递,如果有参数就是使用参数,如果没传参数需要计算
// 通过长度创建一个大buffer Buffer.alloc(len)
// 再循环list将每一项拷贝到大buffer上 buf.copy()
// 如果长度过长fill 或可以通过slice截取有效长度
// 返回新的buffer
if (typeof totalLength === 'undefined') {
totalLength = list.reduce((prev, next) => prev + next.length, 0)
}
let buffer = Buffer.alloc(totalLength)
let offset = 0
list.map(buf => {
if (!Buffer.isBuffer(buf)) throw new Error('not buffer')
buf.copy(buffer, offset)
offset += buf.length
})
return buffer.slice(0, offset)
}
进制转换
base64转换
let buf = Buffer.from()
buf.toString('base64')
一个汉字3个字节,24位。
把一个汉字的24位,转换成4个字节,每个字节就6位,不足的补0。
// base64原理
// 1. 把16进制转化位2禁止 toString()
// 2. 将这些值转化成10进制,去可见编码中取值 parsetInt()
let buf = Buffer.from('五') // <Buffer e4 ba 94>
Buffer.from('五').toString('base64') // 5LqU
console.log((0xe4).toString(2))
console.log((0xba).toString(2))
console.log((0x94).toString(2))
// 11100100 10111010 10010100
// 00111001 00001011 00101010 00010100
console.log(parseInt('00111001', 2))
console.log(parseInt('00001011', 2))
console.log(parseInt('00101010', 2))
console.log(parseInt('00010100', 2))
// 57 11 42 20
// 5 L q U
promise
pormise链
fs
模块既有同步又有异步,异步有callback
,同步有返回值。
同步的读取:fs.readFileSync('file', 'utf8')
, 错误需要try{} catch(){}
- 读取文件,文件必须存在。 不能通过
/
读取内容,/
表示的是根目录。 - 读取的默认类型是
buffer
。
异步: fs.readFile('filename', 'utf8', function (err, data) {})
异步会导致,回调地狱,不方便维护。
如果第一个promise
中返回了一个promise实例,会把当前执行的结果传到下一个then中。
let fs = require('fs')
let util = require('util')
let read = util.promiseify(fs.readFile)
read('filename', 'utf8').then((data) => {
return read(data, 'utf8')
}).then((data) => {
console.log(data)
}).catch(() => {})
async await
await
后面只能跟随promise
Pormise.all()
Promise.resolve() // 返回成功
Promise.reject() // 返回失败
Promise.race()
path
path.join()
: 拼接路径path.resolve()
: 解析绝对路径
流,基于事件。
events
remove
once
on
emit
// 订阅发布
let EventEmitter = require('events')
let { inherits } = require('util')
function Test() {}
let test = new Test()
inherits(Girl, EventEmitter)
test.on('t', function (params) { // 订阅
console.log(1, params)
})
test.emit('t', 2) // 发布
test.removeAllListeners()
可读流和可写流
流:边读边写,不是一次性读取。
let fs = require('fs')
let rs = fs.createReadStream(filename) // 创建可读流,返回rs对象。
需要监听事件,等待数据来到rs.emit()
。
// 默认data事情是不停的触发,直到文件中到数据全部读出来
rs.on('data', (chunk) => { // 默认非流动模式
console.log(chunk) // Buffer
rs.pause(); // 暂停读取, 暂停on('data')
rs.resume(); // 恢复读取
})
// 等数据全部读取完毕执行
rs.on('end', () => {})
// 读取错误执行
rs.on('err', (err) => {})
可写流:ws.write()
, ws.end()
可写流来写入数据必须是字符串类型或Buffer类型
let fs = require('fs')
let ws = fs.createReadStream('a.js');
// 可写流:ws.write() ws.end()
ws.write('1') // 返回布尔值,表示能否还有空间写入
ws.end('end') // 调用end()之后,不可以再使用write()
ws.on('drain', function () { // 全部写入后,就恢复读取
console.log('drain')
})
pipe
#!/usr/bin/bash
let fs = require('fs')
// 30B 读取4B 5次,读取第一次就开始写入,只能写1B,暂停读取,当drain后再恢复读取
function pipe (source, target) {
let rs = fs.createReadStream(source, {highWaterMark: 4})
let ws = fs.createWriteStream(target, {highWaterMark: 1})
// 开启可读流
rs.on('data', function (chunk) {
if (ws.write(chunk) === false) { // 可写流不能再继续写入
rs.pause() // 暂停读取
}
})
let count = 1
ws.on('drain', function () {
console.log(count)
count += 1
rs.resume() // 恢复读取
})
// 全部读取完毕,关闭写入
rs.on('end', () => {
ws.end()
})
// 可以直接使用 pipe()
// rs.pipe(ws) // 可读流.pipe(可写流),会自动调用write和end 方法
}
pipe('a.txt', 'b.txt')
http server
let http = require('http')
let fs = require('fs')
http.createServer((req, res) => {
// req代表客户端 是可读流
// res代表服务端 是可写流
fs.createReadStream('index.html').pipe(res)
}).listen(3000)
fetch
基于 promise
。
fetch(url, {
method: 'GET'
}).then((res) => {
console.log(res.text())
return res.text()
}).then((data) => {
console.log(data)
}).catch(err => {
console.log(err)
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。