js 让网页具有了活力
网景公司出的
瑞恩达尔
node.js 就是js的执行环境和js的扩展功能, 可以运行js的运行环境, 等同于游览器
使用chrome游览器V8为基础搭建一个新的js执行环境, 在V8的基础上添加了服务器编程语言应有的功能, 如文件系统, 模块, 包, 操作系统API, 网络通信,和数据库操作
基于chrome V8 引擎的js 运行环境
node.js包管理工具 npm
node.js 是基于chromev8 引擎的js运行环境, 它是一个事件驱动, 非阻塞式的I/O模型, 。
node.js可以说是chrome游览器的一部分, 但对js功能进行了增强
分支主题 10
架构
x86 64位
x64 32位
node -v 测试版本
repm 模式,直接启动node.exe ,不推荐
文件模式 打开控制台, 在控制台 输入 node
dos命令行
e: 切换盘符, windos系统, / mac 系统
dir window 下显示文件及文件夹列表 ls 显示文件夹
cd 进入文件夹 cd 文件夹名 ,进入指定文件夹
cd ../ // 返回上一级文件夹
cd / // 返回根文件夹, linux mac 系统
运行node.js
REPL 模式
控制台输入 node
可以直接书写js代码
交互式命令行解析器
只适合进行测试,不能开发
直接运行js文件
当前文件的父文件,打开控制台,输入node + 文件名 ,即可执行js文件的内容
退出命令
exit
两次 ctrl + c
cd + 需要打开的文件直接拖过来,可以直接进来
子主题 4
模块化, 三种流行的模块化
cmd
amd
根据AMD规范,我们可以使用define定义模块,使用require调用模块。
commonjs
nodejs 是common.js
定义的变量和函数在一个模块内部,解决冲突和项目依赖问题
amd规范
我们可以使用define定义模块,使用require调用模块。
AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出
AMD 即Asynchronous Module Definition,中文名是“异步模块定义”的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是CommonJS
AMD规范只定义了一个函数 define,它是全局变量。函数的描述为:
define(id?, dependencies?, factory)
id:指定义中模块的名字,可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。
依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。
工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
依赖为空,默认为这三个 应该默认为["require", "exports", "module"]。
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb()
//Or:
return require("beta").verb()
}
})
cmd 规范
commonjs 规范
nodejs 实现了commonjs规范,
js的模块化, 模块的代码都在一个函数中
js的模块的共性
模块的定义的函数和变量都是局部的
模块中有一个模块对象, 包含(module)模块名, exports 导出对象
require.js 模块名可以不写,就是文件名
cmd commonjs 都有导出对象 amd 则使用return 返回
AMD规范
AMD (Asynchronous module defintition 异步模块定义), 这种模块是异步的加载模块, require.js使用这一规范, 适合客户端游览起
AMD定义一个自由遍历啊个或者全局变量使用define函数 define(id ?, dependencies? factory)
第一个参数id 为字符串类型, 表示模块表示,
第二个参数dependencies 表示当前模块的依赖, 已经被模块定义的模块表示的数组字面
第三个, facory 是一个需要进行实例化的函数或者对象 回调函数
define('alpha', ['require', ''exports", 'beta', function('require', 'exports', 'beta') { return beta.verb() // 'or' return require('beta').verb() })
CMD规范
CMD (Common module defined ) 是seajs 推崇的规范
define(factory)
factory 是一个需要进行实例化的函数或者对象
define(function('require', 'exports', 'module'){ // 模块代码 })
内部使用require 引入依赖, 使用exports 导出
common js
commonjs 是诞生比较早
commons 采用同步加载文件的模式, 只适用于服务端(node.js)
node.js 是common.js 的一种实现
二进制, 编码, i o fs 断言, 事件, 工人, 文件系统, 控制台
2009,3出生, 2012年
node.js 采用模块方式, node.js, 所有的代码都在模块中
1 在node.js中所有的功能都是以模块的形式存在,一个文件就是一个模块,所有的代码都在模块中
模块之间存在依赖关系, 我们可以引入模块,模块与模块之间相互独立,如果一个模块需要使用另外一个模块的内容, 需要引入另外模块, 另外一个模块需要进行暴露
3 自定义的模块, 自己写的模块
引入文件 node.js
var obj = require('./node1.js')
console.log(2)
console.log(3434);
console.log(obj);
console.log(obj.showFunc())
console.log(obj)
导出文件 node1.js
var str = '今天星期五,星期六';
exports.str = str;
exports.showFunc = function() {
console.log('可以将模块数据暴露')
}
控制台执行 node node.js
主模块
使用node 命令执行的模块为主模块, 相对于其他模块, 都是其他模块, 命名为main.js index.js, app.js 或者 package.json 文件中 main声明的文件, 整个项目的启动模块,主模块对其他模块进行统筹和调度
Node.js的模块组成,所有用户的代码都在模块中, 模块就是一个文件,模块就是函数
在一个文件中可以执行console.log(arguments)
[Arguments] {
'0': { str: '今天星期五,星期六', showFunc: [Function] },
'1': [Function: require] {
resolve: [Function: resolve] { paths: [Function: paths] },
main: Module {
id: '.',
path: '/Users/dengyunfa/Desktop/quanzhang/node',
exports: [Object],
parent: null,
filename: '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
loaded: false,
children: [],
paths: [Array]
},
extensions: [Object: null prototype] {
'.js': [Function],
'.json': [Function],
'.node': [Function],
'.mjs': [Function]
},
cache: [Object: null prototype] {
'/Users/dengyunfa/Desktop/quanzhang/node/node1.js': [Module]
}
},
'2': Module {
id: '.',
path: '/Users/dengyunfa/Desktop/quanzhang/node',
exports: { str: '今天星期五,星期六', showFunc: [Function] },
parent: null,
filename: '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
loaded: false,
children: [],
paths: [
'/Users/dengyunfa/Desktop/quanzhang/node/node_modules',
'/Users/dengyunfa/Desktop/quanzhang/node_modules',
'/Users/dengyunfa/Desktop/node_modules',
'/Users/dengyunfa/node_modules',
'/Users/node_modules',
'/node_modules'
]
},
'3': '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
'4': '/Users/dengyunfa/Desktop/quanzhang/node'
}
console.log(arguments.callee)
[Function]
console.log(arguments.callee.toString())
function (exports, require, module, __filename, __dirname) {
var str = '今天星期五,星期六'
exports.str = str
exports.showFunc = function() {
console.log('可以将模块数据暴露')
}
exports.str = str
exports.showFunc = function() {
console.log('可以将模块数据暴露2')
}
// console.log(arguments)
console.log(arguments.callee.toString())
}
node.js 自动将文件封装为一个函数第一个参数为exports, 可以个参数为 require , module 模块, filename 当前的文件名 __dirname 当前文件的目录
所有用户编写的代码都自动封装到一个函数中,函数具有5个参数
exports 暴露对象,可以将模块中的数据暴露给引入的地方
var str = '今天星期五,星期六'
exports.str = str
exports.showFunc = function() {
console.log('可以将模块数据暴露')
}
exports.str = str
exports.showFunc = function() {
// console.log('可以将模块数据暴露2')
}
// console.log(arguments)
exports.username = 'zhangsan'
console.log(arguments)
[Arguments] {
'0': { str: '今天星期五,星期六', showFunc: [Function], username: 'zhangsan' },
'1': [Function: require] {
resolve: [Function: resolve] { paths: [Function: paths] },
main: Module {
id: '.',
path: '/Users/dengyunfa/Desktop/quanzhang/node',
exports: [Object],
parent: null,
filename: '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
loaded: false,
children: [],
paths: [Array]
},
extensions: [Object: null prototype] {
'.js': [Function],
'.json': [Function],
'.node': [Function],
'.mjs': [Function]
},
cache: [Object: null prototype] {
'/Users/dengyunfa/Desktop/quanzhang/node/node1.js': [Module]
}
},
'2': Module {
id: '.',
path: '/Users/dengyunfa/Desktop/quanzhang/node',
exports: { str: '今天星期五,星期六', showFunc: [Function], username: 'zhangsan' },
parent: null,
filename: '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
loaded: false,
children: [],
paths: [
'/Users/dengyunfa/Desktop/quanzhang/node/node_modules',
'/Users/dengyunfa/Desktop/quanzhang/node_modules',
'/Users/dengyunfa/Desktop/node_modules',
'/Users/dengyunfa/node_modules',
'/Users/node_modules',
'/node_modules'
]
},
'3': '/Users/dengyunfa/Desktop/quanzhang/node/node1.js',
'4': '/Users/dengyunfa/Desktop/quanzhang/node'
}
require 引用模块的韩素,用于一个模块中引用另外一个模块,并且将子模块暴露的数据赋值给变量
__filename 模块对象 包含了当前模块的所有信息
文件所在位置的全部路径
__dirname 当前模块所有的路径(目录路径)
文件所在位置到父文件名
第三个参数为模块, 包含exports, exports 是module.exports 的一个引用
require 引入函数
是一个函数, 在当前模块,加载另外一个模块
模块的分类
第三方模块
第三方模块, 第三方程序员或者公司开发的模块,先安装再使用, , 安装可以使用npm管理工具
安装可以使用npm 包管理工具, npm install < 包的名称
require('模块名‘)
npm i jquery
var obj = require('./node1.js')
var jquery = require('jquery')
console.log(jquery.toString())
自定义模块
自定义模块, 自己编写的文件就是一个自定义模块
自定义模块引入,需要加./
var obj = require('./node1.js')
var obj1 = require('./require')
console.log(obj1)
node 引入自定义的模块需要加./ 表示相对于当前路径, 如果建立文件夹node_modules ,并将文件塞进去, 再引入,可以不用加./ ,系统模块也是这样引进的
系统模块
node.js开发团队已经开发好的模块,可以直接引用即可shying, 不需要安装也可以shying
fs, http, url, path
const fs = require('fs')
// console.log(fs)
fs.readFile('./text.txt', function(error, data) {
// console.log(data)
if (error) {
console.log(error)
} else {
console.log(data.toString())
console.log(data)
}
})
模块引入
子模块,执行报错, 控制台报错
重复引入模块时, 只执行一次
引用模块
const fs1 = require('./node1.js')
const fs2 = require('./node1.js')
// console.log(fs)
console.log(fs1, fs2)
被引用模块
var str = '今天星期五,星期六'
exports.str = str
exports.showFunc = function() {
console.log('可以将模块数据暴露')
}
exports.str = str
console.log('fdsf')
模块多次引用其他相同模块时, 其他模块会进入缓存区,第一引用会进入缓存区,如果没有,则去找对应的模块, 暴露的数据存进缓存。在此调用则直接调用缓存
引入模块路径出错, 控制台报错
exports 用于表示导出的对象
将模块中需要共享的数据暴露到引用处
module.exports.属性名= 值
node08.js
var username = '张三丰'
function show () {
console.log(username)
}
// 暴露
exports.show = show
node.js
var obj = require('./node08.js')
console.log(obj.show())
exports 是module.exports对象的引用
exports 是,module.export的引用, 不能改指向, 只能增加属性和方法
exports 和module.exports 都指向同一个对象
如果想暴露一个对象可以使用 module.exports = func
真正的暴露对象为module.exports , exports 只是与module.exports 指向同一个内存空间, 可以增加属性,不能赋值, 函数暴露只能使用module.exports = func
推荐使用方式 module.exports
module.方法名=值
module 模块对象
module.exports 真正的暴露对象
module.exports.属性 = 值
module.exports.方法 = 函数
module.exports = 对象或方法
module.id 模块ID 模块名称
module.parent 模块的父级模块
module.filename 文件名和路径
module.children 子模块
module.path 当前的路径, 默认查找模块的路径,数组,包含所有的查找路径,如果当前模块查找不到,则往上查找,一直到根目录。
Node.js的模块分类
系统模块, 核心模块
文件模块
第三方模块
第三方模块的存储位置,几万个文件
自定义的模块
引入文件的后缀为,js , node, json 可以省略不写
npm 包管理工具npm (Node package Manager ) 是基于node.js的包管理工具)
什么包 包就是项目
所有的子模块被主模块调用,就是一个项目,就是一个包
包就是项目, 模块就是文件
package.json package.json 是node.js项目的包描述文件, 以json.格式存在的文件
npm 也是到git下载
创建package.json, 针对一个项目
npm init
npm init -y // 全部以全部yes的形式自动建立一个项目
三段版本, 大版本, 中版本,小版本
大版本, 版本的大量更新
小版本,细微的更新
中版本, 比较大的更改
entry point
项目的主文件名
version 版本
版本协议 MIT
dependencise 项目的依赖信息
devDependencies 开发依赖, 打包部署时, 不会将开发依赖打包进去
script
可以执行的脚本
子主题 1
可以使用npm 命令执行对应的命令, 在package.json 寻找对应scripts脚本命令
自定义的命令, 可以使用 npm run 执行对应的命令搅拌
name 项目名称
description 项目描述
main 项目的主文件信息
npm 包管理工具常用的命令
npm install <包的名称> 安装指定的包或者项目
npm i express
express 页面构建的基本框架
npm i <包的名称>@版本名称
安装指定版本的包
npm i <包的名称> -g
全局安装,安装的路径将在最高登记的node_modules的名录中,全局都可以使用
'/Users/dengyunfa/Desktop/quanzhang/node/node2/node_modules',
'/Users/dengyunfa/Desktop/quanzhang/node/node_modules',
'/Users/dengyunfa/Desktop/quanzhang/node_modules',
'/Users/dengyunfa/Desktop/node_modules',
'/Users/dengyunfa/node_modules',
'/Users/node_modules',
'/node_modules'
npm i <包的名称> --save
将包的名称写入依赖列表
npm i <包的名称> -S
将包的名称写入依赖列表
npm i <包的名称> --save-dev
安装包,并将包写入package.json, 作为开发依赖
npm search <包的名称>
搜索包是存在
npm view <包的名称>
查看包的信息
npm uninstall <包的名称>
卸载包
npm update <包的名称>
更新包的信息
npm i 或者npm install
找到package.json文件,安装所有的依赖
cnpm 淘宝提供的npm 代码仓库, 10min更新一次
npm 是一个文件下载工具
实际上去github.com仓库上去下载资源
https://developer.aliyun.com/mirror/NPM?from=tnpm
安装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
npm.taobao.org
node.js的控制台
console.log() 普通输出语句
console.dir()
console.debug()
console.time(标识)
记时开始
console.timeEnd(标识)
记时结束
console.log('1111')
console.dir('2222')
console.debug('3333')
console.error('333')
console.time('t1')
for (let i = 0
}
console.timeEnd('t1')
断言
console.assert(表达式, 输出文字)
当表达式为假的时候,输出后面的断言
Node 是存在作用域
node.js中的一个文件就是一个模块,模块中使用var 定义的变量为局部变量,只能在本模块中使用
如果想在其他模块中使用,需要暴露
module.exports
const obj = require('./node12')
console.log(obj)
var name = '刘备'
module.exports.name = name
全局的变量, 直接使用global.name 或global.fun 暴露全局的属性和方法, 或者name func 等方式暴露
module.exports.name = name
global.name = name
全局方法的定义, 不需要使用var 或者function 定义
ceshi = () => {
console.log('ceshifunc')
}
全局属性的定义
name = 'ceshide'
不推荐使用
回调函数
缓存区,读取文件读取一部分放到内存,位置就是缓存区。
回调函数又称为回调, ,将a函数作为参数传入b函数中, b函数在运行过程中,根据时机决定是否调用a函数, a函数就是回调函数
function show() {
console.log('今日星期六')
}
setTimeout(show, 2000)
show就是一个回调函数
show所在变量 0X001放入内存栈里面,0X001其指向的东西内存堆里面function show() {
console.log('今日星期六')
}
setTimeout 里面也是回调函数
回调函数的机制
1 定义一个回调函数,就是普通的函数
2 将回调函数的函数引用地址作为参数传递给调用者, (调用者本身也是一个函数)
子主题 3
回调函数的应用
事件的注册
node.js也存在事件函数
事件源.on('事件名', 回调函数)
const http = require('http')
const server = http.createServer()
server.on('request', function(req, res) {
res.writeHead(200, {"Content-type": 'text/html
res.write('<h1>你正在访问node.js服务器</h1>')
res.end()
})
server.listen(80, function(){
console.log('服务器已经启动')
})
服务器启动
异步函数, 回调函数
回调函数不一定是异步,但异步一定存在回调函数
ES6 的promise
jquery.扩展
(function(){
$.fn.show = function() {
var iframe = $('<iframe src = "./data.json"></iframe>').appendTo('body')
iframe.on('load', function() {
var data = $(this.contentDocument).find('body').text()
data = JSON.parse(data)
})
}
})()
$('body').show()
子主题 1
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
jQuery.fn = jQuery.prototype
同步和异步
同步: 上一步的任务完成以后,下一步才能执行
异步: 将比较复杂的任务以任务线程实现,不用等上一步完成后,才执行下一步任务。
setTimeout setInterval 在window下的最小间隔事件为15ms ,苹果系统的最小间隔时间为10ms
Promise 承诺对象
什么是promise, promise 是ES6中新增的承诺对象, 用于对异步操作进行消息的传递
promise的状态
pedding状态
resolve状态
reject状态
状态的更改
pedding 到resolve
pedding 到reject
const fs = require('fs')
// 数据的信息提供给p1
var p1 = new Promise((resolve, reject) => {
fs.readFile('./test.txt', function(err,data) {
if (err) {
reject('数据找不到')
} else {
resolve(data.toString())
}
})
})
p1.then((data) => {
console.log(data)
}, (error) => {
console.log(error)
})
var p2 = new Promise((resolve, reject) => {
fs.readFile('./test2.txt', function(err,data) {
if (err) {
reject('数据找不到')
} else {
resolve(data.toString())
}
})
})
p2.then((data) => {
console.log(data)
}, (error) => {
console.log(error)
})
Promise.all([p1, p2]).then((data)=> {
console.log(data)
}, error => {
console.log(error)
})
缓存区, 所有的数据以流的方式传递, 字节流,或流
在内存区开辟一个空间,用于存放字节区,用于存放需要运算的字节码
一个字节位8个二进制位
创建缓存区
1 创建指定长度的缓存区
var buffer = new Buffer(10)
创建5个字节的缓存区
中文在GBK格式下, 占两个字节
中国的通用信息码表
汉字在UTF-8的模式下,占三个字节
3 按照指定的编码创建缓存区
2 ,用数组创建缓存区,单个元素为字符对应字符的十进制模式下的UTF_-8编码
var buffer1 = new Buffer([97,98,99, 65, 66 ])
console.log(buffer1.toString())
按照指定字符创建缓存区
var buffer = new Buffer('张三')
子主题 7
缓存区的写入
buffer.write('字符串‘)
缓存区的读取
buffer.toString()
缓存区的复制
buffer1.copy(buffer2)
文件系统操作
1 读取文件
由于node.js是服务器的程序,不需要要求读取文件的操作, 在客户端没有这样的操作
将数据从硬盘中读取一节就触发回调函数,实现大文件操作
文件读取有两种方式
1 直接读取
2 流式的读取
直接读取
将硬盘上的所有的内容全部的读入到内存,才触发回调函数
两种写法
、异步
const fs = require('fs')
fs.readFile('./test.txt', function(error, data) {
if (error) {
console.log(error)
} else {
console.log(data.toString())
}
})
锄禾日当午,汗滴禾下土。
谁知盘中餐,粒粒皆辛苦。
同步
const data = fs.readFileSync('./test.txt')
console.log(data.toString())
子主题 2
写文件
1直接写的模式
fs.writeFile('./test3.txt', 'data', function(err) {
if (!err) {
console.log('写文件文成')
} else {
console.log(err)
}
})
const fs = require('fs')
var data = fs.writeFileSync('./test3.txt', 'fsfsfsfsfsf')
console.log(data)
2 文件流的方式写文件
读取文件的信息
fs.stat('文件名', function(error, data) {})
读取对应路径的基本信息
fs.stat('./test.txt', function(error, state) {
if (error) {
console.log(error)
} else {
console.log(state)
console.log(state.isFile()) // 当前文件是不是文件
console.log(state.isDirectory()) // 当前文件是不是一个目录
}
})
Stats {
dev: 16777220,
mode: 33188,
nlink: 1,
uid: 501,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 8335805,
size: 73,
blocks: 8,
atimeMs: 1590241742296.7844,
mtimeMs: 1590241742298.4292,
ctimeMs: 1590241742298.4292,
birthtimeMs: 1590234593120.137,
atime: 2020-05-23T13:49:02.297Z,
mtime: 2020-05-23T13:49:02.298Z,
ctime: 2020-05-23T13:49:02.298Z,
birthtime: 2020-05-23T11:49:53.120Z
}
size 文件的大小,以字节为单位, mtime 文件的修改事件, birthtime 文件的创建事件
返回一个对象, 具有 isFile 方法
计算机基础, 计算机网路基础,数据机构与算法 tcp/ip协议
文件的删除
fs.unlink(path, callback)
机械硬盘的文件信息, 文件信息的文件名存在于扇区, 在扇区可以查找到对应的引用, 根据引用可以查找对应的数据。低级格式化可以查找回数据。删除数据只是断开对应的链接
1 删除空目录
fs.rmdir()
fs.rmdir('./empty', function(error, data){
if (error) {
console.log(error)
} else {
console.log('空目录删除成功')
}
})
const fs = require('fs')
// 删除非空目录
function deldir(path) {
// 读取目录的所有的文件信息
const files = fs.readdirSync(path)
for (let i = 0, len =files.length
const file = files[i]
const state = fs.statSync(path + '/' + file)
const innerPath = path + '/' + file
if (state.isFile()) {
fs.unlinkSync(innerPath)
} else {
// 递归掉用
deldir(innerPath)
}
}
// 删除空目录
fs.rmdirSync(path)
}
deldir('./data')
4 判断如果是文件
fs.unlink()
5 如果是目录,则递归调用自己5
2 读取目录中的文件及文件夹列表
fs.readdir()
6 删除空目录
fs.rmdir()
3 读取每一个文件的详细信息
fs.stat()
流, 所有的互联网传输的数据都是以流的方式,流是字节码, 是一组有起点,有终点的数据传输方式
流的操作
1 流式读取文件
const fs = require('fs')
// 创建可读流
const readStream = fs.createReadStream('./test.txt')
readStream.on('data', function(a){
console.log('------------------------')
console.log(a)
console.log(a.length)
})
一段一段读取数据, 一段流的长度为64KB
stream.on('end', function(data){
console.log('数据读完了')
})
// 写入流报错的事件
stream.on('error', function(error) {
console.log('出错了')
})
2 以流式方式写文件
const stream = fs.createWriteStream('./test4.txt')
stream.write('张三失踪了')
stream.write('李四失踪了')
stream.end()
const stream = fs.createWriteStream('./test4.txt')
stream.write('张三失踪了')
stream.write('李四失踪了')
stream.end()
// 写入流写入完成触发的事件
stream.on('finish', function(){
console.log('写完了')
})
// 写入流报错的事件
stream.on('error', function(error) {
console.log('出错了')
})
管道
管道是一种输出流到输入流的机制, 我们通常用于从一个流中获取数据并经数据传输到另外一个流中
语法
输出流.pipe(输入流)
实现大文件的复制
原来的方式
var readStream = fs.createReadStream('./test.txt')
var writeStream = fs.createWriteStream('./test4.txt')
readStream.on('data', function(data){
writeStream.write(data)
})
readStream.on('end', function() {
writeStream.end()
console.log('文件复制完成')
})
使用管道
s1.pipe(s2)
链式流
将多个管道链接起来, 实现链式处理
const fs = require('fs')
// 创建可读流
const zlib = require('zlib')
const s1 = fs.createReadStream('./test.txt')
const s2 = fs.createWriteStream('./file.txt.zip')
s1.pipe(zlib.createGzip()).pipe(s2)
path 路径模块
path 路径
进行路径转换的模块
path模块是node.js提供的系统模块,不需要安装,用于格式化或者拼接一个完整的路径
path 模块的常用方法
path.normalize()
规范化路径
../../../a/c.html
const path = require('path')
var p1 = '../../../path/../a/./b/../c.html'
console.log(path.normalize(p1))
path.join()
将多个字符串拼接为一个完整路径
path.resolve(to)
将to 解析为绝对路径
linus 中以/ 开始为绝对路径, 网站是以/开头为绝对路径, windows 是以盘名开始的路径为绝对路径
path.isAbsolute(path)
判断对前路径path 是否为绝对路径
path.relative(from , to)
将路径转化为相对路径
path.dirname(path)
返回路径的文件夹部分
var p2 = './day02/hello/zs.html'
console.log(path.dirname(p2))
path.basename(path)
返回路径为文件名和扩展名
path.extname(path)
返回路径的扩展名
path.parse()
// 解析路径,返回一个对象包含路径的各个部分
var p2 = './day02/hello/zs.html'
// console.log(path.dirname(p2))
console.log(path.parse(p2))
{
root: '',
dir: './day02/hello',
base: 'zs.html',
ext: '.html',
name: 'zs'
}
url 路径
http 协议
http 模块
url 全球同一的资源定位符, 地球找资源, 唯一的url,对网络资源的一种简洁表达形式
http 或者 https
协议
www.baidu.com
域名
顶级域名 baidu.com
二级域名, www 或者mail
www
url 的构成
protocal
协议名称
格式为 协议名称://
auth
老版本, user password 用户名和密码
子主题 2
格式为 usrname:password
省略, 匿名访问
http协议, ftp文件上传和下载,需要给出用户名和密码
href 整个网址
域名的格式为
主机名.ming.域
子域名就是主机名
子域名可以随意开
格式为www.baidu.com
:80 80就是端口号
https 的端口号就是8443
域名需要解析为端口号
/path
/ 表示根路径, path 表示路径
?query
get方式传递参数
?a=1&b=2
查询参数
哈希地址, 就是html的锚点链接
完整的结构就是location.href
协议://用户名:密码@主机名.名.域:端口/目录名/文件名.扩展名?参数名=参数值&参数名=参数值
标准格式
一般格式
协议名://主机名.名.域/路径.扩展名?参数名=参数值
node.js url模块
1 在node.js中提供了两套对url进行处理的api功能
1 老的node.js url 模块
var url = require('url')
var u = 'http://music.163.com:80/aaa/index.html?id=10#/discover/playlist'
console.log(url.parse(u))
Url {
protocol: 'http:', // 协议名称
slashes: true,
auth: null, // 没有认证
host: 'music.163.com:80', // 主机名
port: '80', // 端口
hostname: 'music.163.com', // 域名
hash: '
search: '?id=10', // 查询字符串
query: 'id=10', // 查询参数
pathname: '/aaa/index.html', // 路径
path: '/aaa/index.html?id=10',
href:
'http://music.163.com:80/aaa/index.html?id=10
}
2 新的url 模块, (WHATWG URL标准模块)
origin 包含协议,主机名和端口号
URL {
href: 'http://music.163.com/aaa/index.html?id=10
origin: 'http://music.163.com', //
protocol: 'http:',
username: '',
password: '',
host: 'music.163.com',
hostname: 'music.163.com',
port: '',
pathname: '/aaa/index.html',
search: '?id=10',
searchParams: URLSearchParams { 'id' => '10' },
hash: '
}
const {URL} = require('url')
var u = 'http://music.163.com:80/aaa/index.html?id=10#/discover/playlist'
// console.log(url.parse(u))
const myURL = new URL(u)
console.log(myURL)
http协议
网络是信息传输, 接收, 共享的虚拟平台
网络传输数据有一定的规则, 这些规则称为协议, http就是规则的一种。使用最为频繁的一种协议
http 是超文本传输协议, 传输的内容为超文本
它是Tcp/ip协议上一个应用层协议,
规定了网页数据在传输数据的数据格式和交换过程。 传输超文本内容。比如,图片,音频,视频,文字,
http协议规定了数据在服务器和游览器传输的格式和过程
详细的过程分为三次握手,四次挥手
http协议规定的细节
http协议是一种请求应答形式的协议, 一次请求,对应一次应答(响应)
http 协议到底约束了什么
1 定义了游览器以什么格式向服务器发送请求
2 定义了服务器以什么格式解析游览器发送过来的数据
3 定义了服务器以什么格式响应数据给游览起
4 定义了游览起以什么格式解析服务器发送的数据
软件开发模式
1 单机模式 单机软件, 打开电脑可以使用,不需要网络, hbuilder world officer 计算器 ps
2 c s 软件, 客户端/服务器端,需要下载安装后, 才能连接网络使用 , 比如 qq 迅雷
3 b/s 软件 browser / server软件, 游览起/服务器端软件 打开网址就可以使用,百度 淘宝, 京东
saas服务 , 软件即服务
购买账号即可以使用对应的服务
客户端发送请求, 服务器时刻等待着访问, 服务器被请求
游览器输入网址流程
1 首先输入的是域名, 通过DNS服务器, 获取对应域名的解析
2 游览器获取对应的ip地址, 获取对应的服务器
3 如果是静态文件,服务器则将对应的html代码, 就是静态html, 静态的网页, 直接硬盘读取对应的内容
4 通过服务器引擎,获取对应的数据,生成对应的页面,返回给游览器
5 游览器则显示对应的页面
Network 分类
General 部分
Request Url 请求地址
Request method 请求方式
Status code 请求的状态
Remote address 服务器的地址
Response Headers 响应头部
子主题 1
子主题 1
子主题 1
子主题 1
Request Headers 请求头
Connect 连接状态
User-Agent 用户代理
Accet 能够接收的内容
Accept-Encoding 接收的编码
Cache-control 缓存控制
Accept-language 能够接受的语言
Host 主机名
Request body 请求体 post 请求才具有
Responses body 响应主体部分
http模块
http接口被设计成支持
https 被设计成为加密传输
作为客户端,获取数据
1 get方法 get 方法, 模仿客户端可以用于从服务器端获取数据
http.get('url', function(err,data) { })
const http = require('http')
const fs = require('fs')
http.get('http://www.itsource.cn', function(res) {
res.pipe(fs.createWriteStream('./a.html'))
})
作为服务器, 返回数据
网络爬虫
自动获取网络内容的程序
什么是爬虫, 网络爬虫又成为网页蜘蛛或者网络机器人, 是一种按照一定的规则, 自动的抓去万维网信息的程序
2 写一个爬虫程序 nipic.com批量下载图片
开发思路
1. 打开网页查看内容, 找到图盘地址
const http = require('http')
const fs = require('fs')
const path = require('path')
http.get('http://www.nipic.com/design/shengwu/niaolei/index.html', function(res) {
var data = ''
// 以流的方式读取数据
//
res.on('data', function(a) {
data += a.toString()
})
// 当流结束事件
res.on('end', function(){
// console.log(data)
fs.writeFileSync('./bbb.text', data)
// data 就是当前网页的HTML 的内容
// 编写正则表达式提取所有的图片地址
let tempArray = []
var reg = /<img src="http:\/\/static\.nipic\.com\/images\/grey\.gif" data-src="(.+?)" alt=".*?" \/>/img
var result
while((result = reg.exec(data))){
tempArray.push(result[1])
}
getImage(tempArray)
})
})
function getImage (array) {
for (let i = 0, len = array.length
const url = array[i]
const tempUrl = url.replace('\/pic\/', '\/file\/').replace('4.jpg', '2.jpg')
http.get(tempUrl, function(res) {
var fn = new Date().getTime()
// 创建可写流
var stream = fs.createWriteStream('./files/' + fn+'.jpg')
res.pipe(stream)
})
}
}
2 找规律, 查看网页源代码
1小图片 http://pic282.nipic.com/pic/20200411/18500232_223146489000_4.jpg
2 大图片的地址 http://pic282.nipic.com/file/20200411/18500232_223146489000_2.jpg
2 编写代码实现打开网页, 获取所有的html内容
3 通过正则表达式提取有哪些图片地址
4 遍历图片地址数组, 一个一个请求
5 将获取到的图片保存到硬盘上
回调函数
什么是回调函数
回调函数也称为回调, 其实就是一个普通的函数, 将该函数作为另外一个函数的参数传入, 由另外一个函数根据条件执行
回调函数的实现机制
1 定义一个普通的函数
2 将该函数作为一个参数传入另外一个函数中(调用者)
3 调用者函数在具体的时机或者条件达到时, 调用该函数,(回过来再调用该函数)
回调函数的作用
如果我们需要在某一个任务完成后,执行一段代码,可以使用回调函数
异步与同步
什么是同步, 什么是异步
同步, 前一个任务完成后, 后一个任务才能继续执行(会造成阻塞)
异步: 将比较复杂的任务制作成异步模式(回调函数), 后一句代码不需要等待前一句完成后才可以继续执行(不会造成阻塞)
php 同步的单线程,单进程的, 不适合做大型项目, java 是多线程单进程,多使用cpu和内存资源
异步的实现
回调函数
异步一定存在回调函数, 回调函数不一定是异步, (一些同步的情况也会用到回到函数)
事件
事件一般是异步的,如果是用事件对象触发就是同步的
触发事件以后执行一个回调函数,就是异步, 事件源.on(事件类型, 回调函数)
promise 承诺对象
buffer 缓存区
什么是缓存区
缓存区是内存中开辟的存储空间,用于存储字节码的数据
缓存区的操作
1 创建缓存区
1 var buf = new Buffer(10)
2 var buf = new Buffer([97, 98])
2 var buf = new Buffer('张三‘)
2 写缓存区
buf.write('字符串')
3 复制缓存区
buf.copy(buf2)
4 文件的基本操作(直接操作)
1 读取文件内容
fs.readFile('文件路径', function(err, data) {})
// err 就是错误对象, 如果有错,则有值,如果没有错,则没有值 // data 是数据(字符串)
1.1 读取文件的同步版本
const data = fs.readFileSync('文件路径')
// 同步如果遇到错误,自动报错,异步碰到错误,自己处理错误
2 读取文件的信息
fs.stat('文件路径', function(err,data){})
// data 就是文件的信息
// .size 文件大小, .ctime 文件的创建事件 .mtime 文件的修改事件 .atmie 文件的访问时间, 。.birthtime 文件的创建时间
// 方法 .isFile() 判断当前是不是一个文件 .isDirectory() 判断当前是不是一个目录
子主题 5
3 写文件内容(新增和修改)
3 fs.writeFIle('文件路径', 数据内容, function(err){})
// 如果文件内容存在则修改
// 如果文件不存在就增加
删除文件
fs.unlink('文件路径', function(err){})
5 新增目录
fs.mkdir('目录路径', function(err){})
6 读取目录中的文件列表
fs.readdir('目录路径‘, function(err, list){})
// list 就是文件目录列表
7 删除空文件夹
fs.rmdir('文件夹目录', function(err,dta){})
// 只能删除空文件夹,不能删除非空文件夹
5 流式 读写
1 什么是流 流是一组有序的,有起点和终点的字节数据的传输方式(流式) 流的方式成为字节流
2 读取流
1 var stream = fs.createReadStream('文件路径‘)
2 绑定data事件接收数据
stream.on('data', function(data){consoele.log(data)})
// 绑定error错误事件
stream.on('error', function(error){throw error})
// 绑定end结束事件
stream.on('end', function(){console.log('数据读取完毕')})
3 写入路
1 var strema = fs.createWriteStream('文件路径')
2 // 写入数据
stream.write('数据1‘)
stream.write('数据1‘)
stream.end() // 流式写入完毕时,一定需要一个明确的结束标示
stream.on('finish', function() {})
// 绑定finish 数据写入完成事件
stream.on('error', function(error){})
6 管道pipe
1 什么是管道 管道是一种输入流和输出流之间传输数据的机制
管道不需要经过明显经过缓存
管道的写法
输出流.pipe(输入流)
管道的作用
管道可以实现对大文件的操作, (文件的大小超过内存)
7 链式流
1 将多个管道连接起来,进行链式操作
输入流.pipe(中转流).pipe(中转流).pipe(输出流)
使用mstsc 远程桌面地址, 实行远程桌面
tcp/ip 协议, 网络通讯协议, 所有的网络协议
7层网络协议
http 在应用层
物理层
tcp 层协议在网络层
dns解析器
c/window/system32/drivers/etc/hosts
服务器
java 运行tomact
php apache
aspx iis
node.js 开发服务器
const http = require('http')
// 创建服务器
const server = http.createServer()
// 监听request请求事件,当前请求事件发生时就返回数据
server.on('request', function(req, res){
// req: 请求对象, 包含了所有的客户端请求的数据,请求头,请求主体
// res: 响应对象 包含了所有的服务器端发送给客户端的数据,响应头,响应主体
res.write('<h1>Hello Node.js</h1>')
res.write('<h1>hello 111</h1>')
res.end()
})
// 监听80端口
server.listen(80, function(){
console.log('服务器已经运行')
})
1 访问服务器
server.on('request', function(req, res){
// req: 请求对象, 包含了所有的客户端请求的数据,请求头,请求主体
// res: 响应对象 包含了所有的服务器端发送给客户端的数据,响应头,响应主体
if (req.url === '/') {
res.write('<h1>Homepage</h1>')
} else if (req.url === '/article.html') {
res.write('<h1>ArticlePage</h1>')
}else if (req.url === '/about.html') {
res.write('<h1>AboutPage</h1>')
}
res.end()
})
1 打开游览器
2 输入网址 127.0.0.1 本机地址 localhost b
http的状态码
1 什么是状态码, http 协议规定了服务器响应数据时的状态编码,就是状态码
1XX 普通消息, 没有特殊含义
2XX 表示服务器响应成功
200 请求已成功
子主题 2
3XX 表示重定向
301 永久重定向
302 临时重定向, 服务器维护,临时访问
304 数据未更改,使用缓存
4XX 无法访问
400 语义错误
403 权限不够
404 资源不存在
5XX 服务器有错
500 后端程序错误
502 网关错误
503 服务器已奔溃
状态码的使用
res,writeHead('状态码', 响应对象)
响应头
Content-type
响应的文件类型
未指定文件类型,默认为html
text/html
默认编码为系统编码
Content-length
响应内容的长度
// 设置响应头
res.writeHead(200, {"Content-type": 'text/html
res.writeHead(200)
Conent-type : keep-alive 保持连接
"Access-Control-Allow-Origin": "*"
允许所有其他人访问
MiME类型
1 什么是MIME类型, MIME 类型可以认为是文件类型的描述
常见的MIME类型 .html text/html .csss text/css .js text/javascript .png image/png .jpg image/jpg .json text/json 或者 application/json .txt txt/plain
// "Content-type": "text/html
// "Content-type": 'txt/html
// "Content-type": "application/g-zip
服务器搭建
var http = require('http')
const fs = require('fs')
const server = http.createServer()
server.on('request', function(req, res){
if (req.url === '/' || req.url === '/index.html') {
fs.readFile('./www/index.html', function(err,data) {
// res.write('<h1>hello world</h1>')
// res.end()
if (!err) {
res.writeHead(200, { "Content-type": "text/html, charset=utf-8"});
res.write(data);
res.end();
}
})
}
if (req.url === '/css/index.css') {
fs.readFile('./www/css/index.css', function(err,data) {
// res.write('<h1>hello world</h1>');
// res.end();
console.log(434)
if (!err) {
res.writeHead(200, { "Content-type": "text/css, charset=utf-8"});
res.write(data);
res.end();
}
})
}
});
server.listen(80, function(){
console.log('Server is running');
})
客户端向服务器传递数据
1 get 方式, 在url后面通过? 写键值对形式就是get方式传递数据
在node.js可以接收到客户端传递过来的数据
var query = req.url.split('?');
var value = query[1].split('=')[1];
console.log(value)
res.write( ",页面没有找到");