Node.js的读书笔记

  • 书单阅读:

    • 《Node.js开发指南》
    • 《Node.js入门经典》
    • 《Node与Express开发》
    • 《Node即学即用.pdf》
    • 《Node.js实战》
    • 《深入浅出Node.js》
  • Node 能够实时响应高并发请求的平台I/O密集型

    • DIRT程序:数据密集型实时data-intensive real-time程序
    • JavaScript是单线程(串行) 事件处理器在线程空闲之前不会运行。
    • 采用事件驱动(用事件轮询)和非阻塞式异步I/O(异步式I/O 非阻塞式I/O)
    • 使用事件循环(事件队列)和回调是支持异步代码并解决并发问题的高效方式,
  • 调试

    • 1. REPL: 交互式命令行解析器Read-eval-print loop 输入-求值-输出 循环

      • 快捷键:
        • ctrl + c 退出当前终端。
        • ctrl + c 按下两次 - 退出解析器
        • ctrl + d 退出Node REPL
        • 向上/向下查看输入的历史命令
        • Tab 列出当前命令
      • .开头的元命令
        • help列出使用命令
        • break clear清除内存中任何变量或闭包,不需要重启解析器
        • exit将退出Node解析器
        • save filename保存当前的 Node REPL 会话到指定文件
        • load filename载入当前 Node REPL 会话的文件内容。
    • 2. Node调试器:

      • 设置断点debugger,运行 $ node debug app;
      • cont继续执行
      • repl启动REPL,允许查看变量值和执行代码
      • next,n下一步:跳到下一个语句
      • step,s步入:如果是函数就进入当前执行函数中语句,否则跳过
      • out,o步出:跳出当前执行函数
      • backtrace显示当前调用执行帧或调用栈
      • watch(expr)向观察列表中添加表达式,这样在调试器中进入函数或者移动时会显示出来。
      • list(n)列出调试器中当前停止行的前面和后面的n行代码。
    • 3. Node探查器:Inspector:$ npm install -g inspector

      1. --debug--debug-brk的标志启动应用程序,以调试模式运行
      2. 另一终端运行 $ node-inspector&
      3. Webkit浏览器打开 http://127.0.0.1:8080/?port=5858
  • CommonJS 模块规范与Node模块的实现

    • Node模块机制

      1. 模块定义
        • exports 对象用于导出当前模块的方法或变量
        • module 对象,代表模块自身,exports 是 module 的属性
        • 在Node 中,一个文件就是一个模块
      2. 模块标识:传递给require()的参数,小驼峰命名
      3. 模块引用:核心模块,文件模块
        require()方法接受模块标识,以此引入一个模块的API到当前上下文中
        • 路径分析模块标识符分析 模块路径
          • 核心模块优先级仅次于缓存加载,加载过程最快
          • 路径形式文件模块.或..开始的相对路径、以/开始的绝对路径速,度慢于核心模块
          • 非路径形式的文件模块
        • 文件定位
          1.文件扩展名分析 .js .json .node
          2.目录分析和包
        • 编译执行
          • .js文件通过fs模块同步读取后编译执行,头尾包装
            • (function (exports, require, module, __filename, __dirname) {\n, \n});
          • .node文件用C/C++编写的扩展文件,通过dlopen()方法加载最后编译成生成的文件
          •   `json文件`通过fs模块同步读取后,用JSON.parse()解析
            
          •   `.其他扩展名文件`都被当做.js文件载入
            
    • AMD规范

          define([id], [dependences], factory)
      
    • CMD规范

          define(['dep1', 'dep2'], function (dep1, dep2) {
              return function () {};
          });
      
    • 包结构组织包中各种文件

      • 一个存档文件,即一个目录直接打包为.zip或tar.gz格式的文件,安装后解压还原为目录
        • package.json包描述文件
        • bin存放可执行二进制文件
        • lib存放JS代码
        • doc存放目录
        • test存放单元测试用例的代码
        • examples存放如何使用模块的实际示例目录
        • man存放模块的任何手册页目录
        • src存放源文件的文件夹,常用于CoffeeScript文件
        • .gitignore从Git库忽略的文件清单
        • .npmignore在npm注册库忽略的文件清单
        • LICENSE模块授权文件
        • `README.md
    • 模块开发

      • 创建一个返回Hello World的hello()函数的module_name模块

        1. $ npm init;

        2. $ npm link;会将模块全局安装,模块名称采用package.json中给出的名称

        3. 添加主文件lib/module_name.js

              exports.hello = function() {
              return "Hello World";
              };
          
          • 更新package.json
              "main": "./lib/module_name.js
          
        4. test/test_assert.js

              var assert = require('assert');
              var module_name = require('../lib/module_name.js');
          
              /*
              * 测试hello()是否返回正确的字符串
              */
              assert.equal(
              module_name.hello(),
              "Hello World",
              "期待: 'Hello World',得到: "+ module_name.hello()
              );
          
          • 更新packages.json,$ npm test;,
                      "script": {
                      "test": "node ./test/test_assert.js"
                      }
          
  • Node.js核心模块

    • Global Object全局对象:global全局变量的宿主

      • 全局变量:最外层定义变量/"全局对象属性"/"隐式定义变量";

      • console用于提供控制台标准输出

        • console.log()向标准输出流打印字符并以换行符结束
        • console.error()向标准错误流...
        • console.trace()向标准错误流输出当前的调用栈
      • process 进程:描述当前Node.js进程状态的对象,提供了一个与操作系统的简单接口

        • process.cwd()获取程序当前目录
        • process.chdir('目录')改变应用程序目录
        • process.argv命令行参数数组 ["node", "script.js", "--v"...]
        • process.stdout标准输出流process.stdout.write()
        • process.stdin标准输入流
        • process.stderr标准错误流
        • process.exit(code)在程序内杀死进程,退出程序,code为返回的代码,默认为0
        • process.on()监听事件进程 "exit","uncaughtException","SIGINT"
        • process.nextTick(callback)为事件循环设置一项任务
        • process.env.SOMETHING
          • 设置环境变量
            • SET SOMETHING='12345';Window
            • export SOMETHING='123456'UNIX
      • Buffer 缓冲区:处理二进制数据的方式,对原始内存的分配

        • 全局变量类型,是一个比较罕见的不需要 require('buffer') 就可以使用的类

        • 示例场景
          • 通过TCP连接和接收数据
          • 从图像或者压缩文件读取二进制数据
          • 从文件系统读写数据
          • 处理来自网络的二进制数据流
        • 创建 Buffer 类
          • var buffer = new Buffer(10);创建一个带有10个字节的新缓冲区
          • var buffer = new Buffer([10, 20, 30 ,40, 50]);
          • var buffer = new Buffer("github.com/zhilidali", "utf-8");
        • 语法
          • buffer.write(string[, offset[, length]][, encoding])写入缓冲区
            • string写入缓冲区的字符串
            • offset缓冲区开始写入的索引值,默认为0
            • length写入的字节数,默认为buffer.length
            • encoding使用的编码,默认为'utf-8'
            • 返回值返回实际写入的大小,吐过buffer空间不足,则只会写入部分字符串
          • buffer.toString([encoding[, start[, end]]])从缓冲区读取数据
            • encoding使用的编码,默认为utf8
            • start指定开始读取的索引位置,默认为0
            • end结束位置,默认为缓冲区的结尾
            • 返回值解码缓冲区数据并使用指定的编码返回字符串
          • buffer.toJSON()将 Buffer 转换为 JSON对象
          • Buffer.concat(list[, totaLength])缓冲区合并
            • list用于合并的Buffer对象数组列表
            • totalLength指定合并后Buffer对象的总长度
            • 返回一个多个成员合并的新 Buffer 对象
          • buffer.compare(otherBuffer)缓冲区比较,返回一个数字
          • buffer.copy(bufferToCopyTo)拷贝缓冲区,buffer是要被复制的Buffer对象
          • buffer.slice()裁剪缓冲区
          • buffer.length缓冲区长度
        • Buffer.isEncoding(encoding)

        • Buffer.isBuffer(obj)

    • Util实用工具:提供常用函数集合,弥补JS的功能过于精简的不足

      • util.inherits(constructor, superConstrctor)//实现对象间原型继承

            var util = require('util');//引用模块
            function Base() {//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';
            }
        
            var objBase = new Base();
            objBase.showName();//base
            objBase.sayHello();//Hello base
            console.log(objBase);//{ name:'base', base: 1991, sayHello:[Function]}
        
            util.inherits(Sub, Base);//Sub继承Base
            var objSub = new Sub();
            objSub.showName();//sub
            //objSub.sayHello();
            console.log(objSub);//{ name: 'sub'}
        
      • util.inspect(object, [showHidden], [depth], [colors])//将任意对象转换为字符串,常用于调试和错误输出

        • showHidden:true将会输出更多隐藏信息

        • depth:最大递归层数,如果不指定depth,默认递归2层,指定为 null 表示将不限递归层数完整遍历对象。

        • 如果color 值为 true,输出格式将会以 ANSI 颜色编码,通常用于在终端显示更漂亮的效果。

              var util = require('util');
              function Person() {
                  this.name = 'zhilidali';
                  this.toString = function() {
                      return this.name;
                  }
              }
              var obj = new Person();
          
              console.log(util.inspect(obj));
                  //{ name: 'zhilidali', toSring: [Function] }
              console.log(util.inspect(obj, true));
          
      • util.isArray()/util.isRegExp()/util.isDate()/util.isError()

      • util.format()/util.debug()

    • Events事件驱动:可为事件设置监听器和处理器

      • 客户端相比,Node.js中更常见为网络事件

        1. 服务器的响应
        2. 从文件读取数据
        3. 从数据库返回数据
      • events.EventEmitter//事件发射与事件监听功能的封装

        • EventEmitter.on(event, listener)//为指定事件注册一个监听器

        • EventEmitter.emit(event, [arg1], [arg2], [...])//发射事件

        • EventEmitter.once(event, listener)//为指定事件注册一个单次监听器

        • EventEmitter.removeListener(event, listener)//移除指定事件的某个监听器

        • EventEmitter.removeAllListener([event]);//移除[所有]事件的所有监听器

              var EventEmitter = require('events').EventEmitter;
              var emitter = new EventTmitter();
              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', 'byvoid', 1991);//
          
      • error 事件

    • fs文件系统

      • fs.writeFile(filename, data, callback)写入文件
      • fs.appendFile(filename, data, [encoding], [callback(err)]);追加写入
      • fs.exists(filename, [callback(exists)])是否存在,回调唯一参数:文件是否存在的布尔值
      • fs.rename(oldfile, newfile, [callback()])修改名称
      • fs.readFile(filename, [encoding], [callback(err, data)])fs.readFileSync(filename, [encoding])
      • fs.open(path, flags, [mode], [callback(err, fd)])
        • flags
          • r 以读取模式打开文件。
          • r+ 以读写模式打开文件。
          • w 以写入模式打开文件,如果文件不存在则创建。
          • w+ 以读写模式打开文件,如果文件不存在则创建。
          • a 以追加模式打开文件,如果文件不存在则创建。
          • a+ 以读取追加模式打开,如果文件不存在则创建。
        • mode参数用于创建文件时给文件指定权限,默认是 0666
      • fs.read(fd, buffer, offset, length, position, [callback(err, byteRead, cuffer)])指定的文件描述符 fd 中读取数据并写入 buffer 指向的缓冲区对象
    • url

      • url.parse("URL", boolean)解析URL,返回一个json格式的数组
      • url.format()
      • url.resolve()
    • path

      path.normalize()
      path.join()
      path.dirname()
      path.basename()
      path.extname()

    • querystring

      querystring.stringify()
      querystring.parse()

    • child_process 子进程

      • 场景:
        • 复杂等式计算
        • 使用位于node外部的基于系统工具操作数据
        • 执行资源密集型或花费大量时间来完成的操作
        • 执行清理操作
      1. spawn() 使用系统命令 启动一个子进程来执行命令

        • Command想要运行的命令

        • Arguments传递给命令的任何参数

        • options诸如工作目录和环境变量这样的东西

              var spawn = require('child_process').spawn;
              var ping = spawn('ping', [bbc.co.uk]);//生成ping工具的子进程
              ping.stdout.setEncoding('utf8');
              //对子进程侦听,处理从标准输出接收到的数据
              ping.stdout.on('data', function(data) {
                  console.log(data);
              });
              //父进程可侦听子进程的退出事件并做一些处理
              ping.on('exit', function(code, signal) {
                  console.log('子进程被'+signal+'信号杀死');
              });
              ping.kill("SIGINT");//从父进程发送kill信号给子进程
          
      2. exec()

      3. execFile()启动一个子进程来执行可执行文件

      4. fork() 与子进程通信 //创建一个也是Node.js进程的子进程,并提供父子进程通信能力

        • 父Node程序

              var fork = require('child_process').fork;
              var child = fork(__dirname + '/child.js');
              child.on('message', function(m) {
                  //在父进程侦听消息进行处理
              });
              child.send({message: 'Hello child'});//从父进程发送消息给子进程
          
        • child.js程序

              process.on('message', function(m) {
                  //在子进程侦听消息进行处理
              });
              process.send({message: "Hello parent"});
          
    • Cluster 集群

          var cluster = require('cluster');
          cluster.fork();
          cluster.on('death', function(){
              console.log('子进程'+worker.pid+'死掉')
          })
      
    • HTTP 服务器与客户端

      • HTTP服务器

        1. http.Server一个基于事件的 HTTP 服务器
          • request客户端请求到来时,该事件被触发,

            • 提供req和res参数,是http.ServerRequest和http.ServerResponse的实例,表示请求和相应信息

            • http.createServer([requestListener]),是 http 的一个捷径

            • 功能是创建一个 HTTP 服务器并将requestListener 作为 request 事件的监听函数

                  var http = require('http');
                  var server = new http.Server();
                  server.on('request', function (req, res) {
                      res.writeHead(200, {'Content-Type' : 'text/html'})
                      res.write('

              Node.js

              ') res.end('

              Hello World

              ') }); server.listen(3000);
          • connection当TCP连接建立时,该事件被触发,提供一个socket参数,为net.Socket的实例

          • close当服务器关闭时,事件触发

        2. http.ServerRequestHTTP 请求的信息
          data当请求到来时,该事件被触发,chunk参数表示接收到的数据
          end当请求体数据传输完成时,该事件被触发
          close用户当前请求结束时,该事件被触发
        3. 获取GET 请求内容
          通过url.parse手动解析路径中内容
        4. 获取Post 请求内容
        5. http.ServerResponse返回给客户端的信息
          response.writeHead(statusCode, [headers])向请求的客户端发送响应头
          response.write(data, [encoding])向请求的客户端发送响应内容
          response.end([data], [encoding])结束响应,告知客户端所有发送已经完成
      • HTTP 客户端

        • http.request(options,callback)发起HTTP请求,返回一个http.ClientResponse的实例
          • options类关联数组对象
            • host: 请求的域名或IP地址
            • port: 请求网站的端口,默认为80
            • method: 请求方法,默认是GET
            • path: 请求的相对于跟的路径,默认是"/"
            • headers:一个关联数组对象,为请求头的内容
          • callback回调函数,为http.ClientResponse的实例
        • http.get(options, callback)
    • Stream 流:Node移动数据的方式:大数据情况下必须使用流式处理

      • 三个主要流:标准输入/标准输出/标准错误

      • “比如用流读写文件数据时,由于数据是流,意味着在完成文件读取之前,从最初收到几个字节开始,就可以对数据进行操作”

        • var stream = require('stream')
        • var Readable = stream.Readable
        • var Writable = stream.Writable
        • var Duplex = stream.Duplex
        • var Transform = stream.Transform
          使用Stream可实现数据的流式处理,如:
            var fs = require('fs')
            // `fs.createReadStream`创建一个`Readable`对象以读取`bigFile`的内容,并输出到标准输出
            // 如果使用`fs.readFile`则可能由于文件过大而失败
            fs.createReadStream(bigFile).pipe(process.stdout)
        

      Readable 可读流

    • assert断言

      var assert = require('assert');

      • assert.equal(a, b "异常抛出时显示可选");
      • assert.Equal();
      • assert.strictEqual();
  • Node.js重要扩展模块

    • Scoket.io 套接字

      • WebSocket 基本思想是在Web服务器和浏览器之间保持连接持久打开
        使服务器和浏览器可以推送数据,数据交换快
      • Socket.IO 提供通过WebSocket进行通信的一种简单方式
    • ExpressWeb 程序框架

      • 使用 Scaffold脚手架 快速构建,生成套路化代码
        • $ npm install -g express && npm install -g express-generator
        • $ express -e website;建立工程,目录app.js、package.json、public、routes、views
        • $ cd website && npm install;进入工程安装依赖
        • $ npm start;启动
        • 浏览器访问localhost:3000
      • 中间件处理HTTP请求 的 函数
        中间件是有3个参数的函数:请求对象、响应对象、next函数
      • API
        • var express = require('express');
        • var app = express();
        • app.get(path,function(req, res){})根据请求路径来处理客户端发出的GET请求
          路由是指向客户端提供它所发出的请求内容的机制
          • 请求对象
            • req.params//包含 命名过的路由参数的数组
            • req.params(name)//返回命名的路由参数
            • req.query//一个对象,包含以键值对存放的查询字符串参数
            • req.body//一个对象
            • req.route//用于路由调试
            • req.cookies/req.singnedCookies
            • req.headers
            • req.accepts([types])
            • req.ip
            • req.path
            • req.xhr//如果请求由Ajax 发起将会返回true。
            • req.protocol
            • req.secure
            • req.url/req.originalUrl
            • req.acceptedLanguages
          • 响应对象
            • res.status(code)
            • res.set(name,value)
            • res.cookie
            • res.redirect([status],url)
              • 301永久移动
              • 302
              • 303 响应表单提交
        • app.all()可匹配所有HTTP动词,就是说可过滤所有路径的请求,如使用all函数定义中间件,就相当于所有请求都必须先通过此该中间件。
      • app.use([path], function(req, res, next){});
        • req.path
        • req.query.参数名
        • req.param("参数名")
        • req.params.参数名
        • res.send([body|status], [body]);
    • Underscore

          var arr = [1, 2, 3];
          _each(arr, function(n) {
              console.log(n);
          });
      
    • CoffeScript;

    • Request;

    • Optimist;

    • Chai 断言库

  • 知识点

    • 调试

    • 测试

      • 无头浏览器SeleniumPhantomJSZombie

      • Nodeunit

            exports.testName = function(test) {//testName是测试的描述
                test.export(n);//期望的断言数
                test.strictEqual('hello', 'hello');
                test.done();//表示测试完成
            }
        
      • BDD行为驱动开发

        • Vows

          • Vows用平白语句描述功能
            • Description 描述:测试套组的描述
            • Context 上下文:测试运行的上下文
            • Topic 主题:要测试的是什么
            • Vow 宣告:期望在测试中发生的是什么
              var vows = require('vows'),
              assert = require('assert');
          
              vows.describe('比较字符串').addBatch({//Description
                  '当字符串相等时': {//Context
                      topic: "hello",//Topic
                      '他们应该相等': function (topic) {//Vow
                          assert.strictEqual (topic, "hello");
                      }
                  },
                  '当字符串不等时': {
                      topic: "hello",
                      '他们应该不等': function (topic) {
                          assert.notStrictEqual (topic, "there");
                      }
                  }
              }).run();
          
        • Mocha

              var assert = require('assert');
              describe('比较字符串', function(){
                  describe('当字符串相等时', function(){
                      it('应该返回true', function(){
                          assert.strictEqual ("hello", "hello");
                      })
                  })
                  describe('当字符串不等时', function(){
                      it('应该返回false', function(){
                          assert.notStrictEqual ("hello", "there");
                      })
                  })
              })
          
      • TDD测试驱动开发

    • REST表征状态转移(Representational State Transfer)

      HTTP谓词verb

    • 数据持久化

      • 数据存储方法
        • 保存在硬盘或闪存盘上//文件系统持久化
        • 保存在计算机内存中
          process.env.SOMETHING
        • 保存在数据库中
        • 保存在cookie或会话中
    • Template Engine 模板引擎//从页面模板根据一定规则生成 HTML工具

      • 模板视图引擎 JadeHandlebarsejs
        • ejs系统标签//Embedded JavaScript
          • <% code %>JS代码
          • <%= code %>显示替换过HEML特殊字符的内容
          • <%- code %>显示原始HTML内容
        • Handlebars
          • 上下文对象:渲染模板时传递给模板引擎的对象
          • {{! 此处是注释}}
          • 块级表达式: 提供了流程控制、条件执行和可扩展性
      • layout布局(母版页)
      • Partials片段视图/局部模板/局部文件
      • section段落
      • 视图助手
      • 服务器端模板
        支持模板缓存
      • 客户端模板
    • 部署

      • 云托管 平台即服务(Platform as a Server,Paas)
        云计算的基本思想:数据不是存储在自己硬件上,而是存储在别人硬件上
      • Heroku
    • 工具

      • windows命令行工具Console2
      • Windows版的cURL 找到Win32-Generic"区域
        最好选择支持SSL和SSH功能的版本(如跳转另一页面,点击"Download WITHSUPPORT SSL"),
        解压文件,将curl.exe放到PATH路径下或者用户目录

你可能感兴趣的:(Node.js的读书笔记)