ZhenHe17 / blog

个人博客,希望能让各位看官有所收获,喜欢可以 star || watch ^_^ 🎉
169 stars 6 forks source link

学习 node 内置模块 #18

Open ZhenHe17 opened 4 years ago

ZhenHe17 commented 4 years ago

node 提供在服务端执行JS的环境,我们基于 node 提供的模块和功能来开发应用

学习列表

global 全局对象

global 全局对象可以在任何地方访问到,所有其他的全局变量都是 global 的属性。这和浏览器中的window 对象一样。 global 最根本的作用是作为全局变量的宿主。在最外层定义的变量、global对象的属性、未定义直接赋值的变量都属于全局变量。 node 执行的 js 文件属于一个模块,模块不是最外层的,所以文件中声明的变量不会是全局变量。

// $ node test.js
var X = 123
console.log(global.X) // -> undefined
Y = 3333
console.log(global.Y) // -> 3333

global 对象的内置属性

以上几个大家都比较熟悉了

Buffer 类

用于处理二进制数据,Buffer类的实例大小是固定的、在V8堆内存外分配内存。 它和 typedArray 中的 Uint8Array 几乎一样,是由8位整数组成的数组。 node 中读取图片等文件时会返回 buffer 类型的数据

fs.readFile('logo.png',function (err, origin_buffer) {
    console.log(Buffer.isBuffer(origin_buffer))
})

process

process 提供当前进程的信息和控制进程的方法,比如:

queueMicrotask(callback)

将 callback 放入当前微任务队列中执行。

const p = new Promise((resolve, reject)=>{
    resolve()
})
p.then(()=>{
    console.log('promise');
})
queueMicrotask(() => {
    console.log('queueMicrotask');
});
process.nextTick(()=>{
    console.log('nextTick');
})
console.log('task');

输出

task
nextTick
promise
queueMicrotask

TextEncoder

把 UTF-8 编码的值转为 uint8array

const encoder = new TextEncoder();
const uint8array = encoder.encode('这是一些数据');

TextDecoder

还原 TextEncoder 的结果

URL

url 模块提供了两套 API 来处理 URL:一个是旧版本遗留的 API,一个是实现了 WHATWG标准的新 API。

const url = require('url');
const pastUrl =
  url.parse('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');
const newUrl =
  new URL('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');

返回 url 中 origin、pathname、search 等信息。

URLSearchParams

URL实例中的 searchParams 就是 URLSearchParams 的实例,searchParams 是解析 search 得来的键值对,URLSearchParams提供了 set、append、delete 方法处理键值对

const myURL = new URL('https://example.org/?abc=123');
console.log(myURL.searchParams.get('abc'));
// 打印 123
myURL.searchParams.append('abc', 'xyz');
console.log(myURL.href);
// 打印 https://example.org/?abc=123&abc=xyz

WebAssembly

把 C/C++ 等其他语言的代码编译成 .wasm 文件并执行! 这太酷了 中文文档 MDN教程

http、https、http2

这些模块实现了 http、https、http2 协议,也是服务端开发最常用的模块。 常用的方法有:

常用内置类:

const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello, World!\n'); });

server.listen(3000, '127.0.0.1');

express 中的 app.listen() :
``` js
app.listen = function listen() {
  var server = http.createServer(this);
  return server.listen.apply(server, arguments);
};

下面是完整请求流程的例子:

const postData = querystring.stringify({
  'msg': '你好世界'
});

const options = {
  hostname: 'nodejs.cn',
  port: 80,
  path: '/upload',
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData)
  }
};

const req = http.request(options, (res) => {
  console.log(`状态码: ${res.statusCode}`);
  console.log(`响应头: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`响应主体: ${chunk}`);
  });
  res.on('end', () => {
    console.log('响应中已无数据');
  });
});

req.on('error', (e) => {
  console.error(`请求遇到问题: ${e.message}`);
});

// 将数据写入请求主体。
req.write(postData);
req.end();

扩展阅读

NodeJs 中的 http、https 和 http2

v8

v8 模块主要提供查询堆内存信息的方法和序列化 buffer 的方法

getHeapStatistics()

返回有关 V8 堆空间的统计信息

{
  total_heap_size: 7326976,
  total_heap_size_executable: 4194304,
  total_physical_size: 7326976,
  total_available_size: 1152656,
  used_heap_size: 3476208,
  heap_size_limit: 1535115264,
  malloced_memory: 16384,
  peak_malloced_memory: 1127496,
  does_zap_garbage: 0,
  number_of_native_contexts: 1,
  number_of_detached_contexts: 0
}

可以通过观察 number_of_native_contexts 和 number_of_detached_contexts 的值来判断内存泄漏的情况:

serialize(value)、deserialize(buffer)

serialize(value) 将 value 转换成 buffer,deserialize 将 buffer 转换回来。

child_process 子进程

child_process 允许我们创建一个子进程来执行命令或者 js 文件

exec、execFile、fork、spawn 方法都会返回 ChildProcess 实例。

下面代码创建了一个执行 node test.js 命令的子进程:

    var workerProcess = child_process.exec('node test.js ', function (error, stdout, stderr) {
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
    });

    workerProcess.on('exit', function (code) {
        console.log('子进程已退出,退出码 '+code);
    });

cluster 集群

cluster 是为了能充分利用多核系统而提供的模块,它可以创建共享服务器端口的子进程。而 cluster 的底层是用 child_process 实现的。

根据 CPU 核的数量创建子进程

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);

  // 衍生工作进程。
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello, World\n');
  }).listen(8000);

  console.log(`工作进程 ${process.pid} 已启动`);
}

这段代码会带来一个疑惑,为什么所有子进程可以重复监听 8000 端口。这是因为 cluster 模块修改了 listen 方法,端口仅由 master 进程监听了一次。

在实践中,部分业务不需要也不能够由多个子进程一起做(比如每日的定时处理脚本),egg 框架里提出了 Agent 机制。在一个 Master、多个 Worker 的下新加了一个 Agent。Agent 好比是 Master 给其他 Worker 请的一个『秘书』,它不对外提供服务,只给 App Worker 打工,专门处理一些公共事务。

扩展阅读

通过源码解析 Node.js 中 cluster 模块的主要功能实现

多进程模型和进程间通讯

fs

fs 模块提供与文件系统进行交互的 API。

写入文件:

const data = new Uint8Array(Buffer.from('Node.js中文网'));
fs.writeFile('文件.txt', data, (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

读取文件:

fs.readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});

删除整个文件夹:

function delDir(path){
    let files = [];
    if(fs.existsSync(path)){
        files = fs.readdirSync(path);
        files.forEach((file, index) => {
            let curPath = path + "/" + file;
            if(fs.statSync(curPath).isDirectory()){
                delDir(curPath); //递归删除文件夹
            } else {
                fs.unlinkSync(curPath); //删除文件
            }
        });
        fs.rmdirSync(path);
    }
}

util

util.callbackify(original)

将 async 函数或者返回 promise 的函数转成回调风格的函数

const util = require('util');

async function fn() {
  return 'hello world';
}
const callbackFunction = util.callbackify(fn);

callbackFunction((err, ret) => {
  if (err) throw err;
  console.log(ret);
});

util.promisify(original)

将回调风格的函数转成返回 promise 的函数

util.deprecate(fn, msg[, code])

废弃一个函数,调用被废弃的函数会触发警告

util.isDeepStrictEqual(val1, val2)

计算 val1 和 val2 是否深度相等

util.types

提供对内置对象进行类型检查的方法,比如:

总结

随着 node 版本的不断更新,带来了很多激动人心的功能和更强大的性能。充分了解 node 提供的模块可以让我们在开发时得心应手、游刃有余。