nodejs 主线程是单线程(异步)

将后续的逻辑写成函数,传入到当前执行函数中,当执行到函数得到了结果后,执行传入到函数(回调函数)

web 异步

  • setTimeout
  • callback
  • onclick
  • ajax

阻塞不能异步(阻塞是针对内核)
IO操作,读写操作,异步操作(能用异步绝不用同步)
event-driven事件驱动(发布订阅:当前队列,异步队列)

node中文文档

模块

node自带模块化功能,一个js文件就是模块。(闭包)
模块this不是global
每个文件都有局部作用域,不会将属性挂在global上。

全局变量

在所有模块中都可以使用

  • console
  • process 进程,设置环境变量
  • Buffer 缓存区
  • clearImmediate,clearInterval,clearTimeout
  • setImmediate,setInterval,setTimeout

在命令行里配置NODE_ENVexport

异步(下一个队列,在下一个队列的底部):process.nextTick()

存在于模块范围内的全局变量
  • __dirname
  • __filename
  • require()
  • exports
  • module

模块化:低耦合(每个与模块之前没有关系),高内聚(相同代码,相同逻辑放在一起),方便维护,防止代码冲突(命名冲突)。
单例:不能保证一定不冲突,导致调用过长。

浏览器端的模块化:

  • CMD seajs 就近依赖
  • AMD requirejs 依赖前置

node基于规范commonjs,是基于文件的读写node天生自带模块化。

  1. 定义如何创建一个模块,一个js文件就是一个模块
  2. 如何使用一个模块,require()(具有缓存功能,多次引用,只执行一次)
  3. 如何导出一个模块,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

  1. 包名不能和已有一致
  2. 入口文件,做用是整合
  3. 注册账号,如果有账号表示登陆 npm addUser
  4. 发布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类型

image.png

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

  1. 读取文件,文件必须存在。 不能通过/读取内容,/表示的是根目录。
  2. 读取的默认类型是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)
})

alogy
1.3k 声望121 粉丝

// Designer and Developer


« 上一篇
leetcode - 算法