画布 1
Node.js
  Node.js应用的组成
    引入required模块
      require('<module name>')
    创建服务器
    接受请求与响应请求
  使用介绍
    使用 package.json
      package.json 位于模块的目录下，用于定义包的属性
    版本号：语义版本号分为X.Y.Z三位，分别代表主版本号、次版本号和补丁版本号，例如"argv": "0.0.x"表示依赖于0.0.x系列的最新版argv
      如果只是修复bug，需要更新Z位
      如果是新增了功能，但是向下兼容，需要更新Y位
      如果有大变动，向下不兼容，需要更新X位
    NPM 常用命令
      npm install
        本地安装
          将安装包放在 ./node_modules 下
          可以通过 require() 来引入本地安装的包
        全局安装 (安装时加-g)
          将安装包放在 /usr/local 下或者你 node 的安装目录
          可以直接在命令行里使用
        查看安装信息
          查看所有全局安装的模块npm list -g
          查看某个模块npm list <module name>
      npm uninstall
      npm update
      npm search
      创建模块
        npm init：使用 NPM 生成 package.json 文件，生成的文件包含了基本的结果
        npm adduser：接下来我们可以使用以下命令在 npm 资源库中注册用户（使用邮箱注册）
        npm publish：发布模块
      npm help <command>可查看某条命令的详细帮助
      npm cache clear可以清空NPM本地缓存，用于对付使用相同版本号发布新版本代码的人
      npm unpublish <package>@<version>可以撤销发布自己发布过的某个版本代码
    使用淘宝 NPM 镜像
      npm install -g cnpm --registry=https://registry.npm.taobao.org
      cnpm install [name]
  Node.js REPL(交互式解释器)
    Node 自带了交互式解释器，可以执行以下任务
      读取 - 读取用户输入，解析输入了Javascript 数据结构并存储在内存中
      执行 - 执行输入的数据结构
      打印 - 输出结果
      循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出
    使用变量
      变量声明需要使用 var 关键字 var y = 10
    do-while 循环
      do {
... x++;
... console.log("x: " + x);
... } while ( x < 5 );
    下划线(_)变量
      你可以使用下划线(_)获取上一个表达式的运算结果
    REPL 命令
      ctrl + c - 退出当前终端
      ctrl + c 按下两次 - 退出 Node REPL
      ctrl + d - 退出 Node REPL
      向上/向下 键 - 查看输入的历史命令
      tab 键 - 列出当前命令
      .help - 列出使用命令
      .break - 退出多行表达式
      .clear - 退出多行表达式
      .save filename - 保存当前的 Node REPL 会话到指定文件
      .load filename - 载入当前 Node REPL 会话的文件内容
  Node.js 回调函数
    回调函数一般作为函数的最后一个参数出现，回调函数在完成任务后就会被调用，例如，我们可以一边读取文件，一边执行其他命令，在文件读取完成后，我们将文件内容作为回调函数的参数返回
      function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
    阻塞代码实例
      var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序执行结束!");
        $ node main.js
菜鸟教程官网地址：www.runoob.com
程序执行结束!
    非阻塞代码实例
      var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
});
console.log("程序执行结束!");
        $ node main.js
程序执行结束!
菜鸟教程官网地址：www.runoob.com
  Node.js 事件循环
    preliminary
      Node.js 是单进程单线程应用程序，但是因为 V8 引擎提供的异步执行回调接口，通过这些接口可以处理大量的并发，所以性能非常高。
      Node.js 几乎每一个 API 都是支持回调函数的。
      Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。
      Node.js 单线程类似进入一个while(true)的事件循环，直到没有事件观察者退出，每个异步事件都生成一个事件观察者，如果有事件发生就调用该回调函数.
    事件驱动程序
      Node.js 使用事件驱动模型，当web server接收到请求，就把它关闭然后进行处理，然后去服务下一个web请求。
      当这个请求完成，它被放回处理队列，当到达队列开头，这个结果被返回给用户。
      这个模型非常高效可扩展性非常强，因为 webserver 一直接受请求而不等待任何读写操作。（这也称之为非阻塞式IO或者事件驱动IO）
      在事件驱动模型中，会生成一个主循环来监听事件，当检测到事件时触发回调函数。
      实例
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
// 创建事件处理程序
var connectHandler = function connected() {
console.log('连接成功。');
// 触发 data_received 事件
eventEmitter.emit('data_received');
}
// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);
// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){
console.log('数据接收成功。');
});
// 触发 connection 事件
eventEmitter.emit('connection');
console.log("程序执行完毕。");
        $ node main.js
连接成功。
数据接收成功。
程序执行完毕。
  EventEmitter
    events 模块只提供了一个对象： events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
      // 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
    EventEmitter 的每个事件由一个事件名和若干个参数组成，事件名是一个字符串，通常表达一定的语义。对于每个事件，EventEmitter 支持 若干个事件监听器。当事件触发时，注册到这个事件的事件监听器被依次调用，事件参数作为回调函数参数传递。
      //event.js 文件
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
        $ node event.js
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数
    方法
      addListener(event, listener)
        为指定事件添加一个监听器到监听器数组的尾部。
      on(event, listener)
        为指定事件注册一个监听器，接受一个字符串 event 和一个回调函数。
      once(event, listener)
        为指定事件注册一个单次监听器，即 监听器最多只会触发一次，触发后立刻解除该监听器。
      removeListener(event, listener)
        移除指定事件的某个监听器，监听器必须是该事件已经注册过的监听器。
        它接受两个参数，第一个是事件名称，第二个是回调函数名称。
      removeAllListeners([event])
        移除所有事件的所有监听器， 如果指定事件，则移除指定事件的所有监听器。
      setMaxListeners(n)
        默认情况下， EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
      listeners(event)
        返回指定事件的监听器数组。
      emit(event, [arg1], [arg2], [...])
        按监听器的顺序执行执行每个监听器，如果事件有注册监听返回 true，否则返回 false。
    类方法
      listenerCount(emitter, event)
        返回指定事件的监听器数量。
    事件
      newListener
        event - 字符串，事件名称
        listener - 处理事件函数
        该事件在添加新监听器时被触发。
      removeListener
        event - 字符串，事件名称
        listener - 处理事件函数
        从指定监听器数组中删除一个监听器。需要注意的是，此操作将会改变处于被删监听器之后的那些监听器的索引。
      error 事件
        EventEmitter 定义了一个特殊的事件 error，它包含了错误的语义，我们在遇到 异常的时候通常会触发 error 事件。
        当 error 被触发时，EventEmitter 规定如果没有响 应的监听器，Node.js 会把它当作异常，退出程序并输出错误信息。
        我们一般要为会触发 error 事件的对象设置监听器，避免遇到错误后整个程序崩溃。
    继承 EventEmitter
      大多数时候我们不会直接使用 EventEmitter，而是在对象中继承它。包括 fs、net、 http 在内的，只要是支持事件响应的核心模块都是 EventEmitter 的子类。
  Buffer(缓冲区)
    在v6.0之前创建Buffer对象直接使用new Buffer()构造函数来创建对象实例，但是Buffer对内存的权限操作相比很大，可以直接捕获一些敏感信息，所以在v6.0以后，官方文档里面建议使用 Buffer.from() 接口去创建Buffer对象。
    Buffer 与字符编码
      ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话，这种编码是非常快的。
      utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
      utf16le - 2 或 4 个字节，小字节序编码的 Unicode 字符。支持代理对（U+10000 至 U+10FFFF）。
      ucs2 - utf16le 的别名。
      base64 - Base64 编码。
      latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式。
      binary - latin1 的别名。
      hex - 将每个字节编码为两个十六进制字符。
    创建 Buffer 类
      Buffer.alloc(size[, fill[, encoding]])： 返回一个指定大小的 Buffer 实例，如果没有设置 fill，则默认填满 0
      Buffer.allocUnsafe(size)： 返回一个指定大小的 Buffer 实例，但是它不会被初始化，所以它可能包含敏感的数据
      Buffer.allocUnsafeSlow(size)
      Buffer.from(array)： 返回一个被 array 的值初始化的新的 Buffer 实例（传入的 array 的元素只能是数字，不然就会自动被 0 覆盖）
      Buffer.from(arrayBuffer[, byteOffset[, length]])： 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
      Buffer.from(buffer)： 复制传入的 Buffer 实例的数据，并返回一个新的 Buffer 实例
      Buffer.from(string[, encoding])： 返回一个被 string 的值初始化的新的 Buffer 实例
    写入缓冲区
      buf.write(string[, offset[, length]][, encoding])
        string - 写入缓冲区的字符串。
        offset - 缓冲区开始写入的索引值，默认为 0 。
        length - 写入的字节数，默认为 buffer.length
        encoding - 使用的编码。默认为 'utf8' 。
        返回实际写入的大小。如果 buffer 空间不足， 则只会写入部分字符串。
    从缓冲区读取数据
      buf.toString([encoding[, start[, end]]])
        encoding - 使用的编码。默认为 'utf8' 。
        start - 指定开始读取的索引位置，默认为 0。
        end - 结束位置，默认为缓冲区的末尾。
        解码缓冲区数据并使用指定的编码返回字符串。
    将 Buffer 转换为 JSON 对象
      buf.toJSON()
        返回 JSON 对象。
    缓冲区合并
      Buffer.concat(list[, totalLength])
        list - 用于合并的 Buffer 对象数组列表。
        totalLength - 指定合并后Buffer对象的总长度。
        返回一个多个成员合并的新 Buffer 对象。
    缓冲区比较
      buf.compare(otherBuffer);
        otherBuffer - 与 buf 对象比较的另外一个 Buffer 对象。
        返回一个数字，表示 buf 在 otherBuffer 之前，之后或相同。
    拷贝缓冲区
      buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
        targetBuffer - 要拷贝的 Buffer 对象。
        targetStart - 数字, 可选, 默认: 0
        sourceStart - 数字, 可选, 默认: 0
        sourceEnd - 数字, 可选, 默认: buffer.length
        没有返回值
    缓冲区裁剪
      buf.slice([start[, end]])
        start - 数字, 可选, 默认: 0
        end - 数字, 可选, 默认: buffer.length
        返回一个新的缓冲区，它和旧缓冲区指向同一块内存，但是从索引 start 到 end 的位置剪切。
    缓冲区长度
      buf.length;
        返回 Buffer 对象所占据的内存长度。
  Stream(流)
    Stream 有四种流类型
      Readable - 可读操作。
      Writable - 可写操作。
      Duplex - 可读可写操作.
      Transform - 操作被写入数据，然后读出结果。
    Stream 对象都是 EventEmitter 的实例。常用的事件有
      data - 当有数据可读时触发。
      end - 没有更多的数据可读时触发。
      error - 在接收和写入过程中发生错误时触发。
      finish - 所有数据已被写入到底层系统时触发。
    从流中读取数据
      var fs = require("fs");
var data = '';
// 创建可读流
var readerStream = fs.createReadStream('input.txt');
// 设置编码为 utf8。
readerStream.setEncoding('UTF8');
// 处理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
        程序执行完毕
菜鸟教程官网地址：www.runoob.com
    写入流
      var fs = require("fs");
var data = '菜鸟教程官网地址：www.runoob.com';
// 创建一个可以写入的流，写入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据
writerStream.write(data,'UTF8');
// 标记文件末尾
writerStream.end();
// 处理流事件 --> data, end, and error
writerStream.on('finish', function() {
console.log("写入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
        $ node main.js
程序执行完毕
写入完成。
    管道流
      管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。
      var fs = require("fs");
// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');
// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');
// 管道读写操作
// 读取 input.txt 文件内容，并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log("程序执行完毕");
        $ node main.js
程序执行完毕
    链式流
      链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。
      var fs = require("fs");
var zlib = require('zlib');
// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件压缩完成。");
        执行完以上操作后，我们可以看到当前目录下生成了 input.txt 的压缩文件 input.txt.gz。
      var fs = require("fs");
var zlib = require('zlib');
// 解压 input.txt.gz 文件为 input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("文件解压完成。");
        文件解压完成。
  Node.js模块系统
    一个 Node.js 文件就是一个模块，这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
    创建、使用模块
      exports 是模块公开的接口
        exports.world = function() {
console.log('Hello World');
}
      把一个对象封装到模块中
        module.exports = function() {
// ...
}
      获得这个对象
        //main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
      模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时，其接口对象就是要输出的 Hello 对象本身，而不是原先的 exports。
    服务端的模块放在哪里
      Node.js 中自带了一个叫做 http 的模块，我们在我们的代码中请求它并把返回值赋给一个本地变量。
      这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象。
      由于 Node.js 中存在 4 类模块（原生模块和3种文件模块），尽管 require 方法极其简单，但是内部的加载却是十分复杂的，其加载优先级也各自不同。如下图所示：
  函数
    在 JavaScript中，一个函数可以作为另一个函数的参数。我们可以先定义一个函数，然后传递，也可以在传递参数的地方直接定义函数。
    匿名函数
      function execute(someFunction, value) {
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
      函数传递是如何让HTTP服务器工作的
        var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
        我们向 createServer 函数传递了一个匿名函数
  路由
    我们需要的所有数据都会包含在 request 对象中，该对象作为 onRequest() 回调函数的第一个参数传递。但是为了解析这些数据，我们需要额外的 Node.JS 模块，它们分别是 url 和 querystring 模块。
    router.js
      使用路由来将请求以 URL 路径为基准映射到处理程序上
      function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
    server.js
      我们来扩展一下服务器的 start() 函数，以便将路由函数作为参数传递过去
      var http = require("http");
var url = require("url");
function start(route) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
    index.js
      相应扩展 index.js，使得路由函数可以被注入到服务器中
      var server = require("./server");
var router = require("./router");
server.start(router.route);
    启动应用
      node index.js
  全局对象
    JavaScript 中有一个特殊的对象，称为全局对象（Global Object），它及其所有属性都可以在程序的任何地方访问，即全局变量。
      在最外层定义的变量；
      全局对象的属性；
      隐式定义的变量（未定义直接赋值的变量）。
    __filename
      __filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径，且和命令行参数所指定的文件名不一定相同。 如果在模块中，返回的值是模块文件的路径。
    __dirname
      __dirname 表示当前执行脚本所在的
    setTimeout(cb, ms)
      setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。：setTimeout() 只执行一次指定函数。
      返回一个代表定时器的句柄值。
    clearTimeout(t)
      clearTimeout( t ) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。
    setInterval(cb, ms)
      setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。
      返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。
      setInterval() 方法会不停地调用函数，直到 clearInterval() 被调用或窗口被关闭。
    console
      console 用于提供控制台标准输出，它是由 Internet Explorer 的 JScript 引擎提供的调试工具，后来逐渐成为浏览器的实施标准。
      console.log([data][, ...])
      console.info([data][, ...])
        该命令的作用是返回信息性消息，这个命令与console.log差别并不大，除了在chrome中只会输出文字外，其余的会显示一个蓝色的惊叹号。
      console.error([data][, ...])
        输出错误消息的。控制台在出现错误时会显示是红色的叉子。
      console.warn([data][, ...])
        输出警告消息。控制台出现有黄色的惊叹号。
      console.dir(obj[, options])
        用来对一个对象进行检查（inspect），并以易于阅读和打印的格式显示。
      console.time(label)
        输出时间，表示计时开始。
      console.timeEnd(label)
        结束时间，表示计时结束。
      console.trace(message[, ...])
        当前执行的代码在堆栈中的调用路径，这个测试函数运行很有帮助，只要给想测试的函数里面加入 console.trace 就行了。
      console.assert(value[, message][, ...])
        用于判断某个表达式或变量是否为真，接收两个参数，第一个参数是表达式，第二个参数是字符串。只有当第一个参数为false，才会输出第二个参数，否则不会有任何结果。
    process
      它用于描述当前Node.js 进程状态的对象，提供了一个与操作系统的简单接口。
      事件
        exit
          当进程准备退出时触发。
            退出状态码（略）
        beforeExit
          当 node 清空事件循环，并且没有其他安排时触发这个事件。通常来说，当没有进程安排时 node 退出，但是 'beforeExit' 的监听器可以异步调用，这样 node 就会继续执行。
        uncaughtException
          当一个异常冒泡回到事件循环，触发这个事件。如果给异常添加了监视器，默认的操作（打印堆栈跟踪信息并退出）就不会发生。
        Signal 事件
          当进程接收到信号时就触发。信号列表详见标准的 POSIX 信号名，如 SIGINT、SIGUSR1 等。
      属性
        stdout
          标准输出流。
        stderr
          标准错误流。
        stdin
          标准输入流。
        argv
          argv 属性返回一个数组，由命令行执行脚本时的各个参数组成。它的第一个成员总是node，第二个成员是脚本文件名，其余成员是脚本文件的参数。
        execPath
          返回执行当前脚本的 Node 二进制文件的绝对路径。
        execArgv
          返回一个数组，成员是命令行下执行脚本时，在Node可执行文件与脚本文件之间的命令行参数。
        env
          返回一个对象，成员为当前 shell 的环境变量
        exitCode
          进程退出时的代码，如果进程优通过 process.exit() 退出，不需要指定退出码。
        version
          Node 的版本，比如v0.10.18。
        versions
          一个属性，包含了 node 的版本和依赖.
        config
          一个包含用来编译当前 node 执行文件的 javascript 配置选项的对象。它与运行 ./configure 脚本生成的 "config.gypi" 文件相同。
        pid
          当前进程的进程号。
        title
          进程名，默认值为"node"，可以自定义该值。
        arch
          当前 CPU 的架构：'arm'、'ia32' 或者 'x64'。
        platform
          运行程序所在的平台系统 'darwin', 'freebsd', 'linux', 'sunos' 或 'win32'
        mainModule
          require.main 的备选方法。不同点，如果主模块在运行时改变，require.main可能会继续返回老的模块。可以认为，这两者引用了同一个模块。
      方法
        abort()
          这将导致 node 触发 abort 事件。会让 node 退出并生成一个核心文件。
        chdir(directory)
          改变当前工作进程的目录，如果操作失败抛出异常。
        cwd()
          返回当前进程的工作目录
        exit([code])
          使用指定的 code 结束进程。如果忽略，将会使用 code 0。
        getgid()
          获取进程的群组标识（参见 getgid(2)）。获取到得时群组的数字 id，而不是名字。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        setgid(id)
          设置进程的群组标识（参见 setgid(2)）。可以接收数字 ID 或者群组名。如果指定了群组名，会阻塞等待解析为数字 ID 。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        getuid()
          获取进程的用户标识(参见 getuid(2))。这是数字的用户 id，不是用户名。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        setuid(id)
          设置进程的用户标识（参见setuid(2)）。接收数字 ID或字符串名字。果指定了群组名，会阻塞等待解析为数字 ID 。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        getgroups()
          返回进程的群组 iD 数组。POSIX 系统没有保证一定有，但是 node.js 保证有。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        setgroups(groups)
          设置进程的群组 ID。这是授权操作，所以你需要有 root 权限，或者有 CAP_SETGID 能力。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        initgroups(user, extra_group)
          读取 /etc/group ，并初始化群组访问列表，使用成员所在的所有群组。这是授权操作，所以你需要有 root 权限，或者有 CAP_SETGID 能力。
          注意：这个函数仅在 POSIX 平台上可用(例如，非Windows 和 Android)。
        kill(pid[, signal])
          发送信号给进程. pid 是进程id，并且 signal 是发送的信号的字符串描述。信号名是字符串，比如 'SIGINT' 或 'SIGHUP'。如果忽略，信号会是 'SIGTERM'。
        memoryUsage()
          返回一个对象，描述了 Node 进程所用的内存状况，单位为字节。
        nextTick(callback)
          一旦当前事件循环结束，调用回调函数。
        umask([mask])
          设置或读取进程文件的掩码。子进程从父进程继承掩码。如果mask 参数有效，返回旧的掩码。否则，返回当前掩码。
        uptime()
          返回 Node 已经运行的秒数。
        hrtime()
          返回当前进程的高分辨时间，形式为 [seconds, nanoseconds]数组。它是相对于过去的任意事件。该值与日期无关，因此不受时钟漂移的影响。主要用途是可以通过精确的时间间隔，来衡量程序的性能。
          你可以将之前的结果传递给当前的 process.hrtime() ，会返回两者间的时间差，用来基准和测量时间间隔。
  常用工具
    util 是一个Node.js 核心模块，提供常用函数的集合，用于弥补核心 JavaScript 的功能 过于精简的不足。
    util.callbackify
      util.callbackify(original) 将 async 异步函数（或者一个返回值为 Promise 的函数）转换成遵循异常优先的回调风格的函数，例如将 (err, value) => ... 回调作为最后一个参数。 在回调函数中，第一个参数为拒绝的原因（如果 Promise 解决，则为 null），第二个参数则是解决的值。
      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.inherits
      util.inherits(constructor, superConstructor) 是一个实现对象间原型继承的函数。
      JavaScript 的面向对象特性是基于原型的，与常见的基于类的不同。JavaScript 没有提供对象继承的语言级别特性，而是通过原型复制来实现的。
      var util = require('util');
function Base() {
this.name = 'base';
this.base = 1991;
this.sayHello = function() {
console.log('Hello ' + this.name);
};
}
Base.prototype.showName = function() {
console.log(this.name);
};
function Sub() {
this.name = 'sub';
}
util.inherits(Sub, Base);
var objBase = new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
var objSub = new Sub();
objSub.showName();
//objSub.sayHello();
console.log(objSub);
        base
Hello base
{ name: 'base', base: 1991, sayHello: [Function] }
sub
{ name: 'sub' }
    util.inspect
      util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法，通常用于调试和错误输出。它至少接受一个参数 object，即要转换的对象。
      showHidden 是一个可选参数，如果值为 true，将会输出更多隐藏信息。
      depth 表示最大递归的层数，如果对象很复杂，你可以指定层数以控制输出信息的多 少。如果不指定depth，默认会递归 2 层，指定为 null 表示将不限递归层数完整遍历对象。 如果 colors 值为 true，输出格式将会以 ANSI 颜色编码，通常用于在终端显示更漂亮 的效果。
      特别要指出的是，util.inspect 并不会简单地直接把对象转换为字符串，即使该对 象定义了 toString 方法也不会调用。
    util.isArray(object)
      如果给定的参数 "object" 是一个数组返回 true，否则返回 false。
    util.isRegExp(object)
      如果给定的参数 "object" 是一个正则表达式返回true，否则返回false。
    util.isDate(object)
      如果给定的参数 "object" 是一个日期返回true，否则返回false。
  文件系统
    Node 导入文件系统模块(fs)语法：var fs = require("fs")
    打开文件
      fs.open(path, flags[, mode], callback)
        path - 文件的路径。
        flags - 文件打开的行为。具体值详见下文。
        mode - 设置文件模式(权限)，文件创建默认权限为 0666(可读，可写)。
        callback - 回调函数，带有两个参数如：callback(err, fd)。
    获取文件信息
      fs.stat(path, callback)
        path - 文件路径。
        callback - 回调函数，带有两个参数如：(err, stats), stats 是 fs.Stats 对象。
    写入文件
      fs.writeFile(file, data[, options], callback)
        file - 文件名或文件描述符。
        data - 要写入文件的数据，可以是 String(字符串) 或 Buffer(缓冲) 对象。
        options - 该参数是一个对象，包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 ， flag 为 'w'
        callback - 回调函数，回调函数只包含错误信息参数(err)，在写入失败时返回。
    读取文件
      fs.read(fd, buffer, offset, length, position, callback)
        fd - 通过 fs.open() 方法返回的文件描述符。
        buffer - 数据写入的缓冲区。
        offset - 缓冲区写入的写入偏移量。
        length - 要从文件中读取的字节数。
        position - 文件读取的起始位置，如果 position 的值为 null，则会从当前文件指针的位置读取。
        callback - 回调函数，有三个参数err, bytesRead, buffer，err 为错误信息， bytesRead 表示读取的字节数，buffer 为缓冲区对象。
    关闭文件
      fs.close(fd, callback)
        fd - 通过 fs.open() 方法返回的文件描述符。
        callback - 回调函数，没有参数。
    截取文件
      fs.ftruncate(fd, len, callback)
        fd - 通过 fs.open() 方法返回的文件描述符。
        len - 文件内容截取的长度。
        callback - 回调函数，没有参数。
    删除文件
      fs.unlink(path, callback)
        path - 文件路径。
        callback - 回调函数，没有参数。
    创建目录
      fs.mkdir(path[, options], callback)
        path - 文件路径。
        options 参数可以是：
          recursive - 是否以递归的方式创建目录，默认为 false。
          mode - 设置目录权限，默认为 0777。
        callback - 回调函数，没有参数。
    读取目录
      fs.readdir(path, callback)
        path - 文件路径。
        callback - 回调函数，回调函数带有两个参数err, files，err 为错误信息，files 为 目录下的文件数组列表。
    删除目录
      fs.rmdir(path, callback)
        path - 文件路径。
        callback - 回调函数，没有参数。
  GET/POST请求
    获取GET请求内容
      node.js 中 url 模块中的 parse 函数提供了这个功能。
      var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);
    获取 URL 的参数
      我们可以使用 url.parse 方法来解析 URL 中的参数
      var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
res.write("网站名：" + params.name);
res.write("\n");
res.write("网站 URL：" + params.url);
res.end();
}).listen(3000);
    获取 POST 请求内容
      POST 请求的内容全部的都在请求体中，http.ServerRequest 并没有一个属性内容为请求体
      node.js 默认是不会解析请求体的，当你需要的时候，需要手动来做
      var http = require('http');
var querystring = require('querystring');
var util = require('util');
http.createServer(function(req, res){
// 定义了一个post变量，用于暂存请求体的信息
var post = '';
// 通过req的data事件监听函数，每当接受到请求体的数据，就累加到post变量中
req.on('data', function(chunk){
post += chunk;
});
// 在end事件触发后，通过querystring.parse将post解析为真正的POST请求格式，然后向客户端返回。
req.on('end', function(){
post = querystring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
      以下实例表单通过 POST 提交并输出数据：
      var http = require('http');
var querystring = require('querystring');
var postHTML =
'<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js 实例</title></head>' +
'<body>' +
'<form method="post">' +
'网站名： <input name="name"><br>' +
'网站 URL： <input name="url"><br>' +
'<input type="submit">' +
'</form>' +
'</body></html>';
http.createServer(function (req, res) {
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
// 解析参数
body = querystring.parse(body);
// 设置响应头部信息及编码
res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
if(body.name && body.url) { // 输出提交的数据
res.write("网站名：" + body.name);
res.write("<br>");
res.write("网站 URL：" + body.url);
} else { // 输出表单
res.write(postHTML);
}
res.end();
});
}).listen(3000);
  Web 模块
    Web 应用架构
      Client - 客户端，一般指浏览器，浏览器可以通过 HTTP 协议向服务器请求数据。
      Server - 服务端，一般指 Web 服务器，可以接收客户端请求，并向客户端发送响应数据。
      Business - 业务层， 通过 Web 服务器处理应用程序，如与数据库交互，逻辑运算，调用外部程序等。
      Data - 数据层，一般由数据库组成。
    使用 Node 创建 Web 服务器
      server.js
        var http = require('http');
var fs = require('fs');
var url = require('url');
// 创建服务器
http.createServer( function (request, response) {
// 解析请求，包括文件名
var pathname = url.parse(request.url).pathname;
// 输出请求的文件名
console.log("Request for " + pathname + " received.");
// 从文件系统中读取请求的文件内容
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP 状态码: 404 : NOT FOUND
// Content Type: text/html
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
// HTTP 状态码: 200 : OK
// Content Type: text/html
response.writeHead(200, {'Content-Type': 'text/html'});
// 响应文件内容
response.write(data.toString());
}
// 发送响应数据
response.end();
});
}).listen(8080);
// 控制台会输出以下信息
console.log('Server running at http://127.0.0.1:8080/');
    使用 Node 创建 Web 客户端
      client.js
        Node 创建 Web 客户端需要引入 http 模块，创建 client.js 文件
        var http = require('http');
// 用于请求的选项
var options = {
host: 'localhost',
port: '8080',
path: '/index.html'
};
// 处理响应的回调函数
var callback = function(response){
// 不断更新数据
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
// 数据接收完成
console.log(body);
});
}
// 向服务端发送请求
var req = http.request(options, callback);
req.end();
  Express 框架
    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用，和丰富的 HTTP 工具。
使用 Express 可以快速地搭建一个完整功能的网站。
    安装 Express
      $ cnpm install express --save
      $ cnpm install body-parser --save
        node.js 中间件，用于处理 JSON, Raw, Text 和 URL 编码的数据。
      $ cnpm install cookie-parser --save
        这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie，并把它们转成对象。
      $ cnpm install multer --save
        node.js 中间件，用于处理 enctype="multipart/form-data"（设置表单的MIME编码）的表单数据。
    第一个 Express 框架实例
      接下来我们使用 Express 框架来输出 "Hello World"。
      //express_demo.js 文件
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
    请求和响应
      Express 应用使用回调函数的参数： request 和 response 对象来处理请求和响应的数据。
        app.get('/', function (req, res) {
// --
})
      Request 对象
        req.app：当callback为外部文件时，用req.app访问express的实例
        req.baseUrl：获取路由当前安装的URL路径
        req.body / req.cookies：获得「请求主体」/ Cookies
        req.fresh / req.stale：判断请求是否还「新鲜」
        req.hostname / req.ip：获取主机名和IP地址
        req.originalUrl：获取原始请求URL
        req.params：获取路由的parameters
        req.path：获取请求路径
        req.protocol：获取协议类型
        req.query：获取URL的查询参数串
        req.route：获取当前匹配的路由
        req.subdomains：获取子域名
        req.accepts()：检查可接受的请求的文档类型
        req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages：返回指定字符集的第一个可接受字符编码
        req.get()：获取指定的HTTP请求头
        req.is()：判断请求头Content-Type的MIME类型
      Response 对象
        res.app：同req.app一样
        res.append()：追加指定HTTP头
        res.set()在res.append()后将重置之前设置的头
        res.cookie(name，value [，option])：设置Cookie
        opition: domain / expires / httpOnly / maxAge / path / secure / signed
        res.clearCookie()：清除Cookie
        res.download()：传送指定路径的文件
        res.get()：返回指定的HTTP头
        res.json()：传送JSON响应
        res.jsonp()：传送JSONP响应
        res.location()：只设置响应的Location HTTP头，不设置状态码或者close response
        res.redirect()：设置响应的Location HTTP头，并且设置状态码302
        res.render(view,[locals],callback)：渲染一个view，同时向callback传递渲染后的字符串，如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面，这样就不会自动输出了。
        res.send()：传送HTTP响应
        res.end()：在end事件触发后，通过querystring.parse将post解析为真正的POST请求格式，然后向客户端返回。
        res.sendFile(path [，options] [，fn])：传送指定路径的文件 -会自动根据文件extension设定Content-Type
        res.set()：设置HTTP头，传入object可以一次设置多个头
        res.status()：设置HTTP状态码
        res.type()：设置Content-Type的MIME类型
    路由
      var express = require('express');
var app = express();
// 主页输出 "Hello World"
app.get('/', function (req, res) {
console.log("主页 GET 请求");
res.send('Hello GET');
})
// POST 请求
app.post('/', function (req, res) {
console.log("主页 POST 请求");
res.send('Hello POST');
})
// /del_user 页面响应
app.get('/del_user', function (req, res) {
console.log("/del_user 响应 DELETE 请求");
res.send('删除页面');
})
// /list_user 页面 GET 请求
app.get('/list_user', function (req, res) {
console.log("/list_user GET 请求");
res.send('用户列表页面');
})
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {
console.log("/ab*cd GET 请求");
res.send('正则匹配');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
    静态文件
      Express 提供了内置的中间件 express.static 来设置静态文件如：图片， CSS, JavaScript 等。
      你可以使用 express.static 中间件来设置静态文件路径。
        app.use('/public', express.static('public'));
      设置完成后可以直接通过链接访问public目录下的静态文件，如：http://127.0.0.1:8081/public/images/logo.png
    GET 方法
      index.html
        <html>
<body>
<form action="http://127.0.0.1:8081/process_get" method="GET">
First Name: <input type="text" name="first_name"> <br>
Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>
      server.js
        var express = require('express');
var app = express();
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.get('/process_get', function (req, res) {
// 输出 JSON 格式
var response = {
"first_name":req.query.first_name,
"last_name":req.query.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
    POST 方法
      index.html
        <html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
First Name: <input type="text" name="first_name"> <br>
Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>
      server.js
        var express = require('express');
var app = express();
var bodyParser = require('body-parser');
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/process_post', urlencodedParser, function (req, res) {
// 输出 JSON 格式
var response = {
"first_name":req.body.first_name,
"last_name":req.body.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
    文件上传
      index.html
        <html>
<head>
<title>文件上传表单</title>
</head>
<body>
<h3>文件上传：</h3>
选择一个文件上传: <br />
<form action="/file_upload" method="post" enctype="multipart/form-data">
<input type="file" name="image" size="50" />
<br />
<input type="submit" value="上传文件" />
</form>
</body>
</html>
      server.js
        var express = require('express');
var app = express();
var fs = require("fs");
var bodyParser = require('body-parser');
var multer = require('multer');
app.use('/public', express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/file_upload', function (req, res) {
console.log(req.files[0]); // 上传的文件信息
var des_file = __dirname + "/" + req.files[0].originalname;
fs.readFile( req.files[0].path, function (err, data) {
fs.writeFile(des_file, data, function (err) {
if( err ){
console.log( err );
}else{
response = {
message:'File uploaded successfully',
filename:req.files[0].originalname
};
}
console.log( response );
res.end( JSON.stringify( response ) );
});
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
    Cookie 管理
      我们可以使用中间件向 Node.js 服务器发送 cookie 信息，以下代码输出了客户端发送的 cookie 信息：
      // express_cookie.js 文件
var express = require('express')
var cookieParser = require('cookie-parser')
var util = require('util');
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: " + util.inspect(req.cookies));
})
app.listen(8081)
  RESTful API
    REST即表述性状态传递（英文：Representational State Transfer，简称REST）是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。
    HTTP 方法
      GET - 用于获取数据。
      PUT - 用于更新或添加数据。
      DELETE - 用于删除数据。
      POST - 用于添加数据。
    users.json
      {
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher",
"id": 1
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian",
"id": 2
},
"user3" : {
"name" : "ramesh",
"password" : "password3",
"profession" : "clerk",
"id": 3
}
}
        获取用户列表
          var express = require('express');
var app = express();
var fs = require("fs");
app.get('/listUsers', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
        添加用户
          var express = require('express');
var app = express();
var fs = require("fs");
//添加的新用户数据
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.get('/addUser', function (req, res) {
// 读取已存在的数据
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
        显示用户详情
          var express = require('express');
var app = express();
var fs = require("fs");
app.get('/:id', function (req, res) {
// 首先我们读取已存在的用户
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
var user = data["user" + req.params.id]
console.log( user );
res.end( JSON.stringify(user));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
        删除用户
          var express = require('express');
var app = express();
var fs = require("fs");
var id = 2;
app.get('/deleteUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
delete data["user" + id];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例，访问地址为 http://%s:%s", host, port)
})
  多进程
    我们都知道 Node.js 是以单线程的模式运行的，但它使用的是事件驱动来处理并发，这样有助于我们在多核 cpu 的系统上创建多个子进程，从而提高性能。
    每个子进程总是带有三个流对象：child.stdin, child.stdout 和child.stderr。他们可能会共享父进程的 stdio 流，或者也可以是独立的被导流的流对象。
    Node 提供了 child_process 模块来创建子进程，方法有：
      exec - child_process.exec 使用子进程执行命令，缓存子进程的输出，并将子进程的输出以回调函数参数的形式返回。
child_process.exec(command[, options], callback)
        command： 字符串， 将要运行的命令，参数使用空格隔开
        options ：对象，可以是：
          cwd ，字符串，子进程的当前工作目录
          env，对象 环境变量键值对
          encoding ，字符串，字符编码（默认： 'utf8'）
          shell ，字符串，将要执行命令的 Shell（默认: 在 UNIX 中为/bin/sh， 在 Windows 中为cmd.exe， Shell 应当能识别 -c开关在 UNIX 中，或 /s /c 在 Windows 中。 在Windows 中，命令行解析应当能兼容cmd.exe）
          timeout，数字，超时时间（默认： 0）
          maxBuffer，数字， 在 stdout 或 stderr 中允许存在的最大缓冲（二进制），如果超出那么子进程将会被杀死 （默认: 200*1024）
          killSignal ，字符串，结束信号（默认：'SIGTERM'）
          uid，数字，设置用户进程的 ID
          gid，数字，设置进程组的 ID
        callback ：回调函数，包含三个参数error, stdout 和 stderr。
        exec() 方法返回最大的缓冲区，并等待进程结束，一次性返回缓冲区的内容。
      spawn - child_process.spawn 使用指定的命令行参数创建新进程。
child_process.spawn(command[, args][, options])
        command： 将要运行的命令
        args： Array 字符串参数数组
          options Object
          cwd String 子进程的当前工作目录
          env Object 环境变量键值对
          stdio Array|String 子进程的 stdio 配置
          detached Boolean 这个子进程将会变成进程组的领导
          uid Number 设置用户进程的 ID
          gid Number 设置进程组的 ID
        spawn() 方法返回流 (stdout & stderr)，在进程返回大量数据时使用。进程一旦开始执行时 spawn() 就开始接收响应。
      fork - child_process.fork 是 spawn()的特殊形式，用于在子进程中运行的模块，如 fork('./son.js') 相当于 spawn('node', ['./son.js']) 。与spawn方法不同的是，fork会在父进程与子进程之间，建立一个通信管道，用于进程之间的通信。
child_process.fork(modulePath[, args][, options])
        modulePath： String，将要在子进程中运行的模块
        args： Array 字符串参数数组
        options：Object
          cwd String 子进程的当前工作目录
          env Object 环境变量键值对
          execPath String 创建子进程的可执行文件
          execArgv Array 子进程的可执行文件的字符串参数数组（默认： process.execArgv）
          silent Boolean 如果为true，子进程的stdin，stdout和stderr将会被关联至父进程，否则，它们将会从父进程中继承。（默认为：false）
          uid Number 设置用户进程的 ID
          gid Number 设置进程组的 ID
        返回的对象除了拥有ChildProcess实例的所有方法，还有一个内建的通信信道。
  连接 MySQL
    npm install mysql
    查询数据
      var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '123456',
port: '3306',
database: 'test'
});
connection.connect();
var sql = 'SELECT * FROM websites';
//查
connection.query(sql,function (err, result) {
if(err){
console.log('[SELECT ERROR] - ',err.message);
return;
}
console.log('--------------------------SELECT----------------------------');
console.log(result);
console.log('------------------------------------------------------------\n\n');
});
connection.end();
    插入数据
      var addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)';
var addSqlParams = ['菜鸟工具', 'https://c.runoob.com','23453', 'CN'];
//增
connection.query(addSql,addSqlParams,function (err, result) {
if(err){
console.log('[INSERT ERROR] - ',err.message);
return;
}
console.log('--------------------------INSERT----------------------------');
//console.log('INSERT ID:',result.insertId);
console.log('INSERT ID:',result);
console.log('-----------------------------------------------------------------\n\n');
});
    更新数据
      var modSql = 'UPDATE websites SET name = ?,url = ? WHERE Id = ?';
var modSqlParams = ['菜鸟移动站', 'https://m.runoob.com',6];
//改
connection.query(modSql,modSqlParams,function (err, result) {
if(err){
console.log('[UPDATE ERROR] - ',err.message);
return;
}
console.log('--------------------------UPDATE----------------------------');
console.log('UPDATE affectedRows',result.affectedRows);
console.log('-----------------------------------------------------------------\n\n');
});
    删除数据
      var delSql = 'DELETE FROM websites where id=6';
//删
connection.query(delSql,function (err, result) {
if(err){
console.log('[DELETE ERROR] - ',err.message);
return;
}
console.log('--------------------------DELETE----------------------------');
console.log('DELETE affectedRows',result.affectedRows);
console.log('-----------------------------------------------------------------\n\n');
});
  连接 MongoDB
    npm install mongodb
    创建数据库
      var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/runoob";
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
console.log("数据库已创建!");
db.close();
});
    创建集合
      var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/runoob';
MongoClient.connect(url, { useNewUrlParser: true }, function (err, db) {
if (err) throw err;
console.log('数据库已创建');
var dbase = db.db("runoob");
dbase.createCollection('site', function (err, res) {
if (err) throw err;
console.log("创建集合!");
db.close();
});
});
    查询数据
find()
      var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("runoob");
dbo.collection("site"). find({}).toArray(function(err, result) { // 返回集合中所有数据
if (err) throw err;
console.log(result);
db.close();
});
});
    插入数据
insertOne()
insertMany()
      var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("runoob");
var myobj = [
{ name: '菜鸟工具', url: 'https://c.runoob.com', type: 'cn'},
{ name: 'Google', url: 'https://www.google.com', type: 'en'},
{ name: 'Facebook', url: 'https://www.google.com', type: 'en'}
];
dbo.collection("site").insertMany(myobj, function(err, res) {
if (err) throw err;
console.log("插入的文档数量为: " + res.insertedCount);
db.close();
});
});
    更新数据
updateOne()
updateMany()
      var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("runoob");
var whereStr = {"type":'en'}; // 查询条件
var updateStr = {$set: { "url" : "https://www.runoob.com" }};
dbo.collection("site").updateMany(whereStr, updateStr, function(err, res) {
if (err) throw err;
console.log(res.result.nModified + " 条文档被更新");
db.close();
});
});
    删除数据
deleteOne()
deleteMany()
      var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("runoob");
var whereStr = { type: "en" }; // 查询条件
dbo.collection("site").deleteMany(whereStr, function(err, obj) {
if (err) throw err;
console.log(obj.result.n + " 条文档被删除");
db.close();
});
});
    排序
      使用 sort() 方法，该方法接受一个参数，规定是升序(1)还是降序(-1)。
    查询分页
      如果要设置指定的返回条数可以使用 limit() 方法，该方法只接受一个参数，指定了返回的条数。
      如果要指定跳过的条数，可以使用 skip() 方法。
    连接操作
      mongoDB 不是一个关系型数据库，但我们可以使用 $lookup 来实现左连接。
    删除集合
      我们可以使用 drop() 方法来删除集合：
    使用 Promise
      Promise 是一个 ECMAScript 6 提供的类，目的是更加优雅地书写复杂的异步任务。
  其他工具模块
    OS 模块
      提供基本的系统操作函数。
    Path 模块
      提供了处理和转换文件路径的工具。
    Net 模块
      用于底层的网络通信。提供了服务端和客户端的的操作。
    DNS 模块
      用于解析域名。
    Domain 模块
      简化异步代码的异常处理，可以捕捉处理try catch无法捕捉的。