nodejs day3

复习

  1. try-catch 捕获异常
  2. 根据用户不同请求,读取不同HTML文件并返回(带图片、带CSS)
  3. 模拟Apache服务器,处理静态资源请求
  4. 用户请求的 url 对于服务器来说就是一个标识
  5. request对象 和 response 对象
  6. npm 安装和使用
  7. modules 和 packages区别
  8. package.json 文件作用
  9. package-lock.json 文件作用
  10. 服务器端如何获取用户 get 提交的数据
  11. 服务器端如何做重定向操作
  12. “路由” 由哪两部分组成?

今日课程

授课顺序

  1. 完成 get 方式添加新闻、post 方式添加新闻
  2. 完成新闻列表页渲染
  3. 完成新闻详情页渲染
  4. 封装读取 data.json 文件代码
  5. 封装写入 data.json 文件的代码
  6. 封装读取 post 数据的代码
  7. require() 加载模块机制
    • 加载过程
    • 执行原理
  8. node.js 模块化介绍
  9. module、module.exports和exports
  1. 通过设置响应报文头让浏览器实现弹框下载功能
  2. 网页中的 ./ 和 ../ 等相对路径的含义
    • 相对于请求当前页面的url来计算,根据这个url计算出上一级url或者本级url等
    • 最终浏览器会根据相对url(相对路径)计算出绝对路径然后再请求服务器(向服务器发起请求)
  3. Buffer 类型介绍
  4. 通过模块化的方式改造 Hacker News

知识点

  1. node.js 模块化介绍
  2. require() 加载模块机制
  3. get 和 post 请求区别
  4. url 模块使用
  5. querystring 模块使用
  6. underscore 模块使用
  7. node.js 中如何获取 get 请求提交的数据
  8. node.js 中如何获取 post 请求提交的数据
  9. module、module.exports、exports
  10. 前端资源库

课程总结:

  1. 通过 url 模块获取get 提交的数据
  2. 通过监听req 对象的 data 事件和 end 事件,配合 querystring模块获取用户 post 提交的数据
  3. underscore 的 template方法使用
  4. require() 加载机制
  5. module、module.exports 和 exports
  6. 封装 异步回调的方法
  7. node.js 模块的分类

node.js 模块

在 node.js 开发中一个文件就可以认为是一个模块。

一、node.js 模块分类

核心模块 Core Module、内置模块、原生模块

  • fs
  • http
  • path
  • url

所有内置模块在安装node.js的时候就已经编译成 二进制文件,可以直接加载运行(速度较快)
部分内置模块,在 node.exe 这个进程启动的时候就已经默认加载了,所以可以直接使用。

文件模块

按文件后缀来分

如果加载时,没有指定后缀名,那么就按照如下顺序依次加载相应模块

  1. .js
  2. .json
  3. .node(C/C++编写的模块)

自定义模块(第三方模块)

  • mime
  • cheerio
  • moment
  • mongo

二、require 加载模块顺序

  1. 看 require() 加载模块时传入的参数是否以 ‘./‘ 或 ‘../‘ 或 ‘/‘ 等等这样的路径方式开头(相对路径或绝对路径都可以)

  2. 是,那么会按照传入的路径直接去查询对应的模块。

  • 传入的是否为具体的文件名

    • require(‘./test.js’) 是具体的文件名

      • 直接根据给定的路径去加载模块,找到了加载成功,找不到加载失败
    • require(‘./test’); 不是具体的文件名、

      • 第一步:根据给定的路径,依次添加文件后缀 .js、.json、.node进行匹配,如果找不到匹配执行第二步
      • 第二步:查找是否有 test 目录(尝试找 test 包)
        • 找不到:加载失败
        • 找到了:依次在 test 目录下查找 package.json 文件(找到该文件后尝试找 main 字段中的入口文件)、index.js、index.json、index.node,找不到则加载失败
  1. 不是,那么就认为传入的是 “模块名称”(比如:require(‘http’)、require(‘mime’))
  • 是核心模块:直接加载核心模块
  • 不是核心模块
    • 依次递归查找 node_modules 目录中是否有相应的包
      • 从当前目录开始,依次递归查找所有父目录下的 node_modules 目录中是否包含相应的包
      • 如果查找完毕磁盘根目录依然没有则加载失败
      • 打印输入 module.paths 查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// require('http')
// require('mime')


// 情况一:require() 的参数是一个路径
require('./index2.js')

// index2.js
// index2.json
// index2.node
// index2 文件夹 -> package.json -> main(入口文件 app.js -> index.js/index.json/index.node) -> 加载失败
require('ndex2')

// 情况二: require() 的参数不是路径,直接就是一个模块名称
// 1. 先在核心模块中查找,是否有和给定的名字一样的模块。如果有,则直接加载该核心模块。
// require('http')

// 2. 如果核心模块中没有该模块那么就会认为这个模块是一个第三方模块(自定义模块)
// 先会去当前js文件所在的目录下去找是否一个一个 node_modules 文件夹
// require('mime')

require 加载模块注意点

  1. 所有模块第一次加载完毕后都会有 缓存,二次加载直接读取缓存,避免了二次开销

    • 因为有 缓存,所以模块中的代码只在第一次加载的时候执行一次
  2. 每次加载模块的时候都优先从缓存中加载,缓存中没有的情况下才会按照 node.js 加载模块的规则去查找

  3. 核心模块在 Node.js 源码编译的时候,都已经编译为二进制执行文件,所以加载速度较快(核心模块加载的优先级仅次于 缓存加载)

  4. 核心模块都保存在 lib 目录下
  5. 试图加载一个和 核心模块 同名的 自定义模块(第三方模块)是不会成功的

    • 自定义模块要么名字不要与核心模块同名
    • 要么使用路径的方式加载
  6. 核心模块 只能通过 模块名称 来加载(错误示例:require(‘./http’); 这样是无法加载 核心模块 http的 )

  7. require() 加载模块使用 ./ 相对路径时,相对路径是相对当前模块,不受执行 node 命令的路径影响
  8. 建议加载文件模块的时候始终添加文件后缀名,不要省略。

三、补充 CommonJS 规范

  1. CommonJS 规范
  2. 模块的定义
  3. 总结:CommonJS 是为 JavaScript 语言制定的一种 模块规范、编程 API规范
  4. node.js 遵循了 CommonJS规范

关于 node.js 中 Module 详细介绍

自己设计路由实现 Hacker News 网站部分功能

参考网址:https://news.ycombinator.com/

步骤

  1. 实现新闻列表页 - 首页 - index
  2. 实现新闻详情页 - 详情页 - details
  3. 实现新闻添加页 - 提交页 - submit
  4. 实现保存数据功能 - 将数据写入到 .json 文件中
  5. 实现首页数据的动态加载 - 根据.json文件来加载数据

实现思路

规划项目目录结构

  • HackerNews
    • resources
      • css
      • images
    • views(存放html模板页面)
    • data(保存新闻数据 data.json 文件)
    • app.js 文件(该文件即我们写服务器端JavaScript代码的地方,用来处理用户请求)
    • package.json

路由设计

  1. 注意:此处要自己设计路由,而不是像模拟 Apache 静态资源服务器一样

根据不同的请求返回相应的功能

  1. 当请求 //index 时,返回 views/index.html 文件内容
  2. 当请求 /details 时,返回 views/details.html 文件内容
  3. 当请求 /submit 时,返回 views/submit.html 文件内容
  4. 当请求 /r 时,保存用户提交的新闻数据,并将重定向到index页面。
  5. 对于其他以’/resources’开头的都当做静态资源来处理。

知识点

  1. 封装render()函数,将render()函数挂载到response对象上,实现response.render()效果。
  2. 使用underscore模块中的模板引擎功能,渲染index页面中的新闻数据。
  3. 通过 url 模块来处理 get 请求
1
2
3
4
5
6
7
8
// 1. 将 req.url 通过 url 模块来处理
var urlObj = url.parse(req.url, true);

// 1.1 获取用户请求的URL,不带查询字符串
// 注意:此时的reqUrl中不包含 get 的请求参数,只是pathname
var reqUrl = urlObj.pathname.toLowerCase();

// urlObj.query
  1. 服务器端接收 post 提交过来的数据
  2. 通过 querystring 模块将查询字符串转换为 json 对象

JSON在线格式化

JSON在线格式化

url模块介绍

  1. 当服务器处理 get 请求时,用户请求的参数是在 request 的 url 属性中,纯字符串,使用起来并不方便
  2. url 模块可以更方便地解析用户 get 请求提交上来的参数

具体使用

  1. 加载模块 var url = require('url');
  2. 调用parse()方法解析
1
2
3
4
5
6

url.parse(urlString[, parseQueryString[, slashesDenoteHost]]);
var urlObj = url.parse(reqUrl, true);

// url对象的pathname属性,获取不包含查询字符串的url
// url对象的query属性中包含的就是请求字符串的键值对对象

模块化

什么是模块?

  • 每个.js文件就是一个模块
  • 从npm上下载的一个包(可能是由多个文件组成的一个实现特定功能的包)也是一个模块
  • 任何文件或目录只要可以被Node.js通过require()函数加载的都是模块
  • 每个模块就是一个独立的作用域,模块和模块之间不会互相”污染”
  • 我们可以通过编程的方式,指定某个模块要对外暴露的内容(其实就是指定require的返回值,通过require的返回值对外暴露指定内容)。这个对外暴露内容的过程也叫”导出” module.exports

为什么要进行模块化

  • 方便代码管理、项目维护
  • 有助于分工协同开发
  • 模块和模块之间不会出现变量”污染”,一个模块就是一个作用域。
  • 模块化可以做到职责分离,每个模块实现一个独立的功能

补充:面向对象编程的5(6)大原则:

  • 开放封闭原则
  • 里氏替换原则
  • 依赖倒置原则
  • 单一职责原则
  • 接口隔离原则

什么是包?

  • 通过package.json描述的一个文件或目录(可以理解成一个实现某个功能的1个文件或多个文件,通过package.json组织起来)
  • 包不一定能被Node.js通过require()来加载,那么就不就叫模块。比如有些包中没有设置启动文件(package.json中的main字段),就不是模块。
  • package 和 module 参考链接

在Node.js中模主要分为:核心模块 和 文件模块

核心模块

  • http、fs、path、url、net、os、readline、……
  • 核心模块在Node.js自身源码编译时,已经编译成二进制文件
  • 部分核心模块在Node.js进程启动的时候已经默认加载到缓存里面了

文件模块(包含独立文件模块和第三方模块)

  • 文件模块可以是:.js 模块、.node模块、*.json模块,这些都是文件模块
  • 无论从npm上下载的第三方模块还是我们自己编写的模块都是文件模块

module.exports 和 exports

在每个模块中module表示当前模块对象, 里面保存了当前模块对象的各种信息

module.exports 其实就是 require()加载模块时的返回值

exports 就是module.exports的一个引用

1
exports = module.exports;

特别注意:最终暴露给require的返回值的是:module.exports, 而不是exports

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  // To illustrate(说明) the behavior, imagine this hypothetical implementation of require(), which is quite similar to what is actually done by require():

function require(...) {
var module = { exports: {} };


((module, exports) => {
// Your module code here. In this example, define a function.
function some_func() {};
exports = some_func;
// At this point, exports is no longer a shortcut to module.exports, and
// this module will still export an empty default object.
module.exports = some_func;
// At this point, the module will now export some_func, instead of the
// default object.
})(module, module.exports);


return module.exports;
}

require 加载模块时做了2件事

  1. 执行了模块中的代码
  2. 返回了模块中对外暴露的内容(可能是对象、函数等等)

下载Node.js源码,打开看下

JavaScript 的严格模式—— "use strict";'use strict';

art-template

  1. npm 搜索:art-template

  2. 参考链接
    https://www.npmjs.com/package/art-template
    art-template文档

-------------本文结束感谢您的阅读-------------
0%