流月
  • CSS
  • JavaScript
  • Web API
  • TypeScript
  • 框架

    • React
    • Vue
  • 其他

    • 小程序
    • 工程化
    • 性能优化
    • 测试
    • 其他
  • nodejs
  • deno
  • express
  • nginx
  • docker
  • 其他
  • 安全基础
  • 正则表达式
  • 网络基础
  • 设计模式
  • 数据结构与算法
  • LeetCode
  • CodeWars
  • 手写代码
  • Git
  • devops
  • 编码原则
  • 防御编程
  • Chrome
  • Edge
  • Flutter
  • Linux
  • 库
  • 网站
  • 面试
  • 摘抄
  • 方法论
  • 语法
  • 王小波
  • Elon Musk
  • CSS
  • JavaScript
  • Web API
  • TypeScript
  • 框架

    • React
    • Vue
  • 其他

    • 小程序
    • 工程化
    • 性能优化
    • 测试
    • 其他
  • nodejs
  • deno
  • express
  • nginx
  • docker
  • 其他
  • 安全基础
  • 正则表达式
  • 网络基础
  • 设计模式
  • 数据结构与算法
  • LeetCode
  • CodeWars
  • 手写代码
  • Git
  • devops
  • 编码原则
  • 防御编程
  • Chrome
  • Edge
  • Flutter
  • Linux
  • 库
  • 网站
  • 面试
  • 摘抄
  • 方法论
  • 语法
  • 王小波
  • Elon Musk
  • Node.js

Node.js

安装nodejs

  • 包管理工具安装
    sudo apt-get install nodejs

  • 直接下载文件

tar -xvf node-v8.4.0-linux-x64.tar.xz
ln -s node-v8.4.0-linux-x64/bin/node /usr/local/bin/node
ln -s node-v8.4.0-linux-x64/bin/npm /usr/local/bin/npm

核心模块

构建高性能网络应用 非阻塞IO 异步 事件轮询 单线程 一个拥有大量共享状态的大进程

1 process对象

2 global对象

__filename
__dirname
setTimeoute
setInterval
console
exports
module
process
require
setImmediate

3 path

path.resolve 用于将相对路径转化为绝对路径
__dirname: 总是返回被执行的 js 所在文件夹的绝对路径
__filename: 总是返回被执行的 js 的绝对路径
process.cwd(): 总是返回运行 node 命令时所在的文件夹的绝对路径

4 EventEmitter

5 buffer

如果没有提供编码格式,文件操作以及很多网络操作就会将数据作为 Buffer 类型返回。

toString

data URI

6 utils 实用工具

util.inherits 原型继承
util.inspect 将任意对象转化为字符串
util.promisify 返回一个返回值是一个 promise 版本的函数。

promisify

const util = require('util');
const fs = require('fs');
const readAsync = util.promisify(fs.readFile);

async function init() {
  try {
    let data = await readAsync('./package.json');

    data  =JSON.parse(data);

    console.log(data.name);
  } catch (err) {
    console.log(err);
  }
}

7 http

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

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

server.listen(port, hostname, () => {
  console.log(`服务器运行在 http://${hostname}:${port}/`);
});

8 stream 流

理解流

流是基于事件的 API,用于管理和处理数据。

  • 流是能够读写的
  • 是基于事件实现的一个实例

理解流的最好方式就是想象一下没有流的时候怎么处理数据:

  • fs.readFileSync 同步读取文件,程序会阻塞,所有数据被读到内存
  • fs.readFile 阻止程序阻塞,但仍会将文件所有数据读取到内存中
  • 希望少内存读取大文件,读取一个数据块到内存处理完再去索取更多的数据

9 child_process 子进程

  • 4个异步方法:exec、execFile、fork、spawn
  • 3个同步方法:execSync、execFileSync、spawnSync
  • 通过 API 创建出来的子进程和父进程没有任何必然联系

exec

execFile

fork

spawn

spawn方法创建一个子进程来执行特定命令,用法与execFile方法类似,但是没有回调函数,只能通过监听事件,来获取运行结果。它属于异步执行,适用于子进程长时间运行的情况。

var child_process = require('child_process');

var path = '.';
var ls = child_process.spawn('/bin/ls', ['-l', path]);
ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

ls.on('close', function (code) {
  console.log('child process exited with code ' + code);
});

10 url

url.hash/host/search/origin
const { URL } = require('url');
const myURL = new URL('https://example.org/foo#bar');
console.log(myURL.hash);
  // 输出 #bar

myURL.hash = 'baz';
console.log(myURL.href);

11 querysting

querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
// 返回 'foo=bar&baz=qux&baz=quux&corge='

querystring.parse('foo=bar&abc=xyz&abc=123') = {
  foo: 'bar',
  abc: ['xyz', '123']
}

querystring.escape()

12 assert

assert.deepEqual(obj1, obj2);
assert.ok(obj1, obj2);

13 crypto

crypto 模块提供了加密功能,包含对 OpenSSL 的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装。

14 events

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('触发了一个事件!');
});
myEmitter.emit('event');

15 fs 文件系统

fs.stat 读取文件夹
  stats.isDirectory()
  stats.isFile()
fs.createReadStream('test.txt');

16 readline

const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('你认为 Node.js 中文网怎么样?', (answer) => {
  // 对答案进行处理
  console.log(`多谢你的反馈:${answer}`);

  rl.close();
});

rl.prompt();


网络

全局变量

require

module.export 和 exports

路径变量 __dirname

console

process

学习

nodebestpractices

Node.js 的意义

  • Serverless
    • Node.js 的轻量化、容易分散与水平扩充、各种操作系统都容易运行的特性,将 Node.js 作为无服务器服务优先支持的框架,这也让 Node.js 更适合用于超大规模部署的应用
  • BFF
    • 引入 Node.js 做 BFF 这样的 API proxy 中间层,使得 API 开发也成了前端的工作范围
    • 让后端同学专注于开发 RPC 服务
  • SSR
  • 工程化工具

语义化版本规范semver

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改,
  • 次版本号:当你做了向下兼容的功能性新增,
  • 修订号:当你做了向下兼容的问题修正。

第一个版本: 0.0.1

cli

  1. 彩色输出 ANSI转义码
console.log('\033[90m' + 'some info' + '\033[39m');
  • \033表示转义序列的开始
  • [ 表示开始颜色设置
  • 90表示前景色为亮灰色
  • m表示颜色设置结束

持久化

  1. node-mogno
  2. node-mysql
  3. node-redis

测试

单元测试

  1. mocha
  2. nodeunit
  3. Vows

断言库

  1. should.js
  2. assert
  3. expect.js 这个好用

覆盖率 coverage

istanbul

验收测试

  • Tobi
  • Soda

npm 命令

npm remove <name> 移除包
npm ls --depth 0 查看当前工程下的包
npm update <name> 更新模块
npm publish 发布模块

部署平台

  1. heroku
  2. now

生产环境部署

  • 将 NODE_ENV 设置为 “production”
  • 保证你的应用在发生错误后自动重启
  • 使用集群模式运行你的应用 多核优势
  • 缓存请求结果
  • 使用负载均衡
  • 使用反向代理 Nginx代理静态文件

异步编程

理解node的事件循环,在浏览器中,事件可能是用户的点击 scroll input等,而在nodejs中,可以是socket的data事件,或者readFile的error事件。

  • 针对一次性的事件,使用回调函数;
  • 针对重复性事件,使用eventEmitter。

流程控制

  1. 串行和并行
  2. 社区工具
  • nimble
  • async
  • step

子进程

var exec = require('child_process').exec

node monolithic 单体架构

monolithic 单体架构

?> 单体架构是一种很自然的搭建应用的方式,它符合我们对业务处理流程的认知。但单体应用也存在问题:任何一处,无论大小的修改都会导致整个应用被重新构建和重新部署。随着应用规模和复杂性的不断增大,参与维护的人数增多,每一轮迭代修改的模块增多,对上线来说是极大的考验,对于内部单个模块的拓展也是极为不利的。例如当图片压缩请求剧增时,需要新增图片压缩模块的实例,但实际上不得不扩展整个单体应用的实例。

缺点:

  • 修改,任意一个功能模块,别的功能模块都要跟着被修改。

改变:

  • 使用微服务架构

后端服务要满足2个特性

  • 能容错 fault tolerant
  • 可扩展 scaclability

高并发下的多进程、负载均衡

多进程的目的,是尽可能利用多核 CPU,提高单机的负载能力。

!> 我们都知道NodeJS程序是以单进程形式运行,32 位机器上最多也只有 1GB 内存的实用权限(在64位机器上最大的内存权限扩大到1.7GB。而目前绝大部分线上服务器的CPU都是多核并且至少16GB 内存起,如此以来 Node 程序便无法充分发挥机器的潜力。

所以,Node 允许程序创建多个子进程用于运行多个实例。

?> 你知道,生产机器的每个 CPU 内核都运行一个 Node Worker 进程,然后负载所有的请求吗?

一般而言,一个 CPU 对一个 Worker 就行了。

了解一下nodejs cluster模块。

集群(cluster)模块可以被用来在多核 CPU 环境负载均衡。基于子进程的 fork 方法并且主要允许我们根据 CPU 核数衍生很多次主应用进程。然后主进程将接管并且通过主进程与所有的子进程的交流实现负载均衡。

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

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

  1. 启动 app.js ,当前执行进程是主线程
  2. 然后会 fork 与cpu个数一样的worker进程
  3. worker进程默认执行 process.argv[1] 文件,即 app.js
  4. 当非 master 进程程启动 http server ,每个worker进程启动一个

1590823081336-16bdd63f-9783-48ca-93e4-3b19ec4b311b.png

多进程的弊端

  • 负载均衡
    • 负载均衡算法
    • node cluster 采用 round-robin 算法策略分发 http 请求到不同 worker 进程
  • Session 共享
    • 假如某个用户第一次访问该服务分配给了线程A上的实例A处理,并且用户在这个实例上进行了登录,没过多久,用户第二次访问被分配给了线程B上的实例B处理。如果用户在A上的登录状态没有共享给其他实例的话,那么用户不得不重新登录一下,这样的用户体验是无法接受的。
  • 反向代理
    • 适用于多台机器多个实例

前端同学不太懂这两个。

平滑不停机重启

error first callback

用一个回调函数 返回两种结果

  • Success返回第一个参数是null 第二个参数是res

  • Error返回第一个参数是error

回调函数里面判断是否存在error

什么叫做有服务端开发的经验?

能说出大概的服务端技术 包括但不限于:

  • docker;
  • k8s;
  • 中后台架构分层
  • 缓存处理
  • 分布式;
  • 响应式编程等。
  • rpc原理
    • rpc服务调用
  • 负载均衡
    • Nginx负载均衡
      • 主备
    • Node应用负载均衡

分布式

异常处理

处理未捕获的异常

上线实践

使用 winston 记录日志

使用 nginx 反向代理

Node 处理 CPU 密集型任务,如 gzipping,SSL termination 等,表现糟糕。

相反,使用一个真正的中间件服务像 Nginx 更好。

检测有漏洞的依赖项

https://docs.npmjs.com/cli/audit

性能优化

V8 内存管理与垃圾回收

分析 GC 日志

使用 headdump 堆快照

benchmark

使用 prof 进行性能分析

应用安全清单

转义 HTML、JS 和 CSS 输出

验证传入的 JSON schemas

限制每个用户允许的登录请求

使用非 root 用户运行 Node.js

使用反向代理或中间件限制负载大小

在沙箱中运行不安全代码

csurf 防止 CSRF

综合应用

Node.js REST API

jwt

Web API 设计

node-schedule 使用

生成 excel

  • js-xlsx : 目前 Github 上 star 数量最多的处理 Excel 的库,支持解析多种格式表格XLSX / XLSM / XLSB / XLS /CSV,解析采用纯js实现,写入需要依赖nodejs或者FileSaver.js实现生成写入Excel,可以生成子表Excel,功能强大,但上手难度稍大。不提供基础设置Excel表格api例单元格宽度,文档有些乱,不适合快速上手;https://github.com/SheetJS/js-xlsx
  • node-xlsx : 基于Node.js解析excel文件数据及生成excel文件,仅支持xlsx格式文件;https://github.com/mgcrea/node-xlsx
  • excel-parser : 基于Node.js解析excel文件数据,支持xls及xlsx格式文件,需要依赖python,太重不太实用;https://github.com/leftshifters/excel-parser
  • excel-export : 基于Node.js将数据生成导出excel文件,生成文件格式为xlsx,可以设置单元格宽度,API容易上手,无法生成worksheet字表,比较单一,基本功能可以基本满足;https://github.com/functionscope/Node-Excel-Export
  • node-xlrd : 基于node.js从excel文件中提取数据,仅支持xls格式文件,不支持xlsx,有点过时,常用的都是XLSX 格式。

fake rest api

  1. https://gorest.co.in/
  2. https://jsonplaceholder.cypress.io/
  3. https://jsonplaceholder.typicode.com/
  4. https://my-json-server.typicode.com/

Egg.js 插件

  • egg-validate 验证客户端请求参数
  • egg-password
  • egg-socket.io
  • egg-session
  • egg-graphql
  • egg-logger
  • egg-multipart
  • eslint-config-egg
  • egg-sequelize
  • egg-static
  • egg-schedule
  • egg-security
  • egg-http-proxy
  • egg-cookies
  • egg-mongoose
  • egg-mysql
  • egg-redis
Last Updated: 7/4/20, 3:40 AM
Contributors: wangqi