nodejs

什么是Node.js

Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

与JavaScript的区别

  • 基于异步I/O接口,读写文件、网络请求等
  • 提供require这种CommonJs的模块化
  • 提供了C++的API可以与底层系统交互

可以干什么?

  • Web服务端:Web Server、爬虫
  • CLI命令行脚本:webpack
  • GUI客户端软件:VSCode、网易云音乐
  • IoT,图像处理,实时通讯,加密货币…

Node.js基础

运行

1
node index.js

读写文件

1
2
3
4
5
6
const fs = require('fs');
fs.readFile('test.txt',(err,data)=>{
console.log(data)
});
console.log('read file content');
// 先read file content 后文件内容

模块

  • 内置模块,编译进node中,例如http fs net process path等,直接require
  • 文件模块,原生模块之外的模块,和文件一一对应,通过文件夹查找形式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 定义文件模块circle.js
    const pi = Math.PI;
    exports.area = function(r){
    return pi * r * r;
    }
    // 在app.js中使用文件模块
    var circle = require('./circle.js');
    console.log('半径为4的圆的面积是:'+ circle.area(4));

模块加载

1
2
3
4
5
6
7
8
9
10
11
//绝对路径
require('/foo/bar/a.js');
//相对路径
require('../a.js');
//加载无后缀的文件
require('../a');
//加载外部模块(依次向上查找)
require('pkg-name');

模块类型

  • .js
  • .json
  • .node(c++写完后编译成二进制文件)
  • .mjs(基于module的exports导入导出)

模块路径查找

  • 绝对路径
  • 相对路径:和当前路径处理为绝对路径
  • 模块/文件夹
    • 原生模块,直接读取缓存
    • [$NODE_PATH,~/.node_modules,./node_modules,../node_modules,...]
    • 解析package.json,查找main属性,没有则使用index.js
    • 如果以上都没找到,报错

js模块解析

  • 通过fs.readFileSync同步拿到文件内容
  • 对内容进行包装,用闭包包装

    1
    2
    3
    4
    (function(exports,require,module,__filename,__dirname){
    var circle = require('./circle.js');
    console.log('The area is ' + circle.area(4));
    });
  • 通过vm.runInThisContext(虚拟沙盒)执行

  • 获取module对象的值作为模块的返回值

模块缓存

  • 模块加载后会将返回值缓存
  • 下次加载时直接读取缓存结果,避免文件I/O和解析时间
  • 导出对象缓存在Module._cache对象上

NPM包管理器(node package manager)

包管理的一些规范

  • 一个package.json文件存在于包顶级目录下
  • 二进制文件在bin目录下
  • js代码在lib目录下
  • 文档在doc目录下
  • 单元测试在test目录下

package.json

  • main:node查找的入口文件,没有的话使用默认的index.js
  • npm scripts:常用的脚本执行的快捷方式
  • dependencies:依赖家族的五个(dependenciesdevDependenciespeerDependenciesbundledDependenciesoptionalDependencies^1.2.2允许中版本和小版本的更新,~0.5.0允许小版本的更新,不接受中版本更新,*接受任意版本的更新,0.0.2只安装这个版本,不更新
  • semver version:a.b.c: a大版本(重构)b中版本(特性的增加)c小版本(bug等)
  • bin:命令名称为key,本地文件名称为value的map
  • registry:代理

npm的问题

  • 在国内的速度问题
  • 安全问题(模块删除…)
    • npm audit检测模块漏洞
    • 外部的检测服务

基于Node.js的Web开发

基础web

1
2
3
4
5
const http = require('http');
const server = http.createServer((req,res) => {
res.end('Hello World'); //拿到用户请求以后修改响应
});
server.listen(3000);

Koa

1
2
3
4
5
6
7
8
9
const Koa = require('koa');
const app = new Koa();
//response
app.use(ctx =>{
ctx.body = 'Hello koa';
})
app.listen(3000);
  • 提供了middleware把逻辑进行拆分,use方法:把fn推到中间件里
  • 无规范约束,不利于团队开发,中间件繁多,质量参差不齐,选择困难。(比如逻辑分层、路由处理、数据解析校验、权限校验、session和cookie、数据库和redis、安全…

API: RESTful 接口规范

  • 每个API都对应一种资源或者资源集合
  • 使用HTTP Method来表示对资源的动作
  • 使用HTTP Status Code来表示资源操作结果

Node.js的调试

  • 日志调试(代码中console)
  • 断点调试
    • node --inspec,在chrome://inspect中可以看到项目,启动devtool
    • vscode的断点调试
    • chrome的ndb模块,可以接在任意node命令前面,代码可以实时修改

Node开发角色转换

  • 前端
    • 跟浏览器打交道,兼容性问题
    • 组件化
    • 加载速度、JS执行性能、渲染性能
    • 错误监控
    • XSS、CSRF等安全漏洞
  • 服务端
    • 数据库、Redis等周边服务
    • 性能、内存泄漏、CPU、机器管理
    • 服务监控、错误监控、流量监控、报警
    • SQL注入、目录遍历等安全漏洞