模块化与 npm
前端 JS:与浏览器交互
后端 Node.js:在服务器(和系统进行交互)端运行 JS、跨平台
Node 是对 ES 标准一个实现,Node 也是一个 JS 引擎通过 Node 可以使 JS 代码在服务器端执行
Node 仅仅对 ES 标准进行了实现,所以在 Node 中不包含 DoM 和 BOM
Node 中可以使用所有的内建对象
string Number Boolean Math Date RegExp Function object Array
而 BoM 和 DOM 都不能使用
但是可以使用 console 也可以使用定时器( setTimeout () setInterval() )
Node 可以在后台来编写服务器
Node 编写服务器都是单线程的服务器
- 进程:进程就是一个一个的工作计划(工厂中的车间)
- 线程:线程是计算机最小的运算单位(工厂中的工人)
线程是干活的传统的服务器都是多线程的
- 每进来一个请求,就创建一个线程去处理请求
Node 的服务器单线程的
- Node处理请求时是单线程,但是在后台拥有一个 I/O 线程池
模块化
- Node 中,一个 JS 文件就是一个 模块
- Node 中,每一个 JS 文件中的 JS 代码都是独立运行在一个函数中,而不是全局作用域,所以一个模块中的变量和函数在其它模块中无法访问
向外部暴露属性或方法 exports.
var x = 'mmmmm1';
var y = 'm11111';
function f() {
console.log('f');
}
exports.f = f;//暴露函数
exports.a = 'engureguo';//暴露属性
exports.x = x;
var m1 = require('./01.m.js');
console.log(m1);
//{ f: [Function: f], a: 'engureguo', x: 'mmmmm1' }
核心模块:服务器级别的 API,被封装到包中
- fs 文件系统工具包
- http 服务器工具包
- path 处理路径相关
- os 查看CPU、内存、用户等信息
- ...
核心模块引入
- node引擎提供的模块
- 核心模块标识,就是模块的名字
var fs = require('fs');
文件模块
- 相对路径,以 . 或 .. 开头
- 绝对路径
全局对象 global,保存全局的 属性和方法
创建全局变量:
a = 0;
global.x = 1;
验证:一个JS文件独立运行在一个函数中,而不是全局作用域,别的模块无法访问
console.log(arguments);//函数入参
console.log(arguments.callee);//当前执行的函数对象
console.log(arguments.callee + "");//查看函数实现
------------------------
function (exports, require, module, __filename, __dirname) {
var m1 = require('./01.m.js');
console.log(arguments);
console.log(arguments.callee + "");
}
实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时传递进了五个实参(global.arguments)
arguments | 含义 | index |
---|---|---|
exports | 该对象用来将变量或函数暴露到外部 | 0 |
require | 函数,用来引入外部的模块 | 1 |
module | 代表当前模块本身,exports 是 module 的属性。module.exports = exports,也可以 module.exports 导出 | 2 |
__filename | 模块绝对路径 | 3 |
__dirname | 模块所在文件夹 | 4 |
[Arguments] {
'0': {},
'1': [Function: require] {
resolve: [Function: resolve] { paths: [Function: paths] },
main: Module {
id: '.',
path: 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws',
exports: {},
parent: null,
filename: 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\demo.js',
loaded: false,
children: [Array],
paths: [Array]
},
extensions: [Object: null prototype] {
'.js': [Function (anonymous)],
'.json': [Function (anonymous)],
'.node': [Function (anonymous)]
},
cache: [Object: null prototype] {
'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\demo.js': [Module],
'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\01.m.js': [Module]
}
},
'2': Module {
id: '.',
path: 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws',
exports: {},
parent: null,
filename: 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\demo.js',
loaded: false,
children: [ [Module] ],
paths: [
'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\node_modules',
'C:\Users\HiWin10\Desktop\notes\其他\node.js\node_modules',
'C:\Users\HiWin10\Desktop\notes\其他\node_modules',
'C:\Users\HiWin10\Desktop\notes\node_modules',
'C:\Users\HiWin10\Desktop\node_modules',
'C:\Users\HiWin10\node_modules',
'C:\Users\node_modules',
'C:\node_modules'
]
},
'3': 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws\demo.js',
'4': 'C:\Users\HiWin10\Desktop\notes\其他\node.js\code-ws'
}
module.exports 与 exports 的区别
module.exports 可以实现 exports 的功能,还可以:
module.exports {
name: 'engure',
age: 22,
say: function() {}
}
栈内存和堆内存
var a = xxx; var b = a; b++; a ? b
基本数据类型保存的数据相互独立,区别于引用类型
exports 指向 module.exports
exports = { } 相当于 exports = new Object();
相当于修改了指向,是错误的用法
总结:
- 通过 exports 只能使用
.
的方式向外部暴露对象 - 通过 module.exports 既可以通过
.
的方式,有可以通过直接赋值{}
问题:以上是讲师所讲内容,在我的机器上 node 14.17.1,可以通过 exports = {} 进行赋值
实验总结:两者的关系是开始时指向同一个对象,是引用类型,如果其中之一又创建了对象(={},或 =new Object()),那么两者指向不同
版本问题?
包
package.json,包的描述信息
dependencies 依赖的包
description
devDependencies 开发依赖,开发环境,区别于生产环境
directories
dist
licence
homepage
maintainers
repository
name 模块标识
...
json 文件不能写注释
NPM 包管理器
Node Package Manager
npm -v
npm version
npm search 包名
npm install 包名(install 可以简写为
i
)npm init
npm remove 包名 (remove 可以简写为
r
)⭐ npm install 包名 --save(安装包并安装到依赖中,--save 可简写为
-S
)安装的同时将包设置在dependencies
中,记录依赖包和他的版本,push到git上时不传node_modules/
中的内容⭐ npm install 安装依赖,自动根据版本下载包
npm install -g 包名 全局安装,一般都是一些工具
如何在一个指定的目录下使用一个 npm 上的包比如 math?
npm init
(一路回车,包名不允许大写)npm install math
此时 math 被安装到 node_modules
中node index.js
var math = require('math');
console.log(math.add(100, 200));
CNPM
下载大包很慢,使用淘宝镜像,China NPM
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm 命令和 npm 一样
cnpm i express -S
看到下载的文件保存方式和原来的 npm 保存方式不一样。
使用快捷方式指向包的方式,避免两者的冲突
node 搜索包的流程?⭐
node 使用模块名字来引入模块时,首先在当前目录的 node_modules 下寻找,如果找不到会去上一级继续找,如果没有则继续向上找,一直找到根目录,如果找不到则报错
commonJS 与 ES6
package.json
中定义 type 字段
// util.js
exports.name = '123';
exports.age = 22;
exports.fun = function () {
console.log('function');
}
//js.js
var { name } = require('./util.js')// 通过 { x } 部分引入
var obj = require('./util.js') // 全部引入
console.log(name)
console.log(obj);
module.exports 与 exports 用法:zhuanlan.zhihu.com/p/87729137
浏览器端的应用,使用 browserify
进行语法转化
blog.csdn.net/dreams_deng…
大环境所致:技术变革,前后端分离,前端的业务变的越来越复杂。
es6 让 javascript 第一次支持 module(浏览器环境)
前提:使用 npm init -y
初始化包,并指定 type: module
//m1.js
var name = 'engure';
var sayHello = function () {
console.log('hello')
}
export var name; // 同名
export var sayHello;
//m2.js
export default {
college: 'cup',
type: 'undergraduate'
}
//app.js
import { name, sayHello } from './m1.js'
import * as m1 from './m1.js'
import obj from './m2.js'
console.log(name);
console.log(m1);
console.log(obj)
浏览器端的使用
Document
// 定义模块
指定type!
import { name, sayHello } from './m1.js'
console.log(name)
// 引入模块
Buffer 与 fs 模块
Buffer
和数组很像,操作方法也相似
与数组不同的是,它能够存储二进制数据
不需要引入,Node自带,直接用
var str = 'Hello Engure!';
//将一个字符串保存到buffer中,
var buf = Buffer.from(str);
console.log(buf);
//
//范围 00~ff, 0000-0000 ~ 1111-1111,以字节为单位
buffer 占用的内存:buffer长度个字节
一个汉字占用 3 个字节
//
console.log(Buffer.from('盖特'));
Buffer 简单使用
所有构造方法都已经废弃了
Buffer.alloc(size)
Buffer大小一旦分配,其长度固定不变,是对内存进行直接操作。(区别于数组)
//数组越界:自动分配空间
var arr = [1,2,3];
arr[5] = 5;
console.log(arr);
//[ 1, 2, 3, , 5 ]
赋值&取值
var buf = Buffer.alloc(10);
buf[0] = 88;
buf[1] = 255;//ff
buf[2] = 0xaa;
buf[3] = 450;//超过255会取低8位
//查看内容
buf[2] //默认10进制
buf[2].toString(16); //16进制内容
buf[2].toString(2); //2进制
//循环
for (var i=0;i= len 字节的内容
创建目录
fs.mkdir(path [, mode], callback)
fs.mkdirSync(path [, mode])
删除目录
fs.rmdirSync(path)
fs.rmdir(path, callback)
文件重命名
fs.rename(oldPath, newPath, callback)
fs.rename(oldPath, newPath)
fs.rename('by.mp3', 'by1.mp3', function (err) {
if (!err){
console.log("修改成功!");
}
});
不同目录下,文件移动功能
//不同目录下,类似文件移动功能
fs.rename('by.mp3', 'F:/by1.mp3', function (err) {
if (!err){
console.log("修改成功!");
}
});
文件的监视
fs.watchFile(filename [, options], listener)
fs.watchFile('f5.txt', function (cur, pre) {
//console.log(arguments);
//cur 当前的Stats
//pre 之前的Stats
console.log(pre.size, '->', cur.size);
});
设置 options.interval
属性,配置轮询频率
fs.watchFile('f5.txt', {interval: 100}, function (cur, pre) {
console.log(pre.size, '->', cur.size);
});
注意:如果设置的太小很消耗性能
http 模块
var http = require('http');
var server = http.createServer();
//注册request请求事件
server.on('request', function () {
console.log(arguments)
});
//启动服务器,需要绑定端口号
server.listen(80, function () {
console.log("server starting...");
});
请求处理
//注册request请求事件,回调函数需要接受两个参数
// Request对象,获取客户端的一些信息,比如URL
// Responce对象,用来给用户发送响应消息
server.on('request', function (req, resp) {
console.log('请求路径 = ' + req.url);
//write可以多次,必须以end结束,告诉给客户端写入已经结束了
resp.write('hello node.js.');
resp.end();
});
req.url
都是以 /
开头,是用户请求的路径
可以根据请求路径 req.url
响应不同的内容
server.on('request', function (req, resp) {
console.log('请求路径 = ' + req.url);
//区别对待不同的请求
if (req.url == '/' || req.url == '/index.html' || req.url == '/index') {
//主页
resp.write('index');
} else if (req.url == '/hello') {
//hello页
resp.write('hello bro!
');
} else {
//404
resp.write('page not found');
}
resp.end();
});
js 中字符串的比较 www.w3school.com.cn/js/js_strin…
Response 中的 Content-Type ⭐⭐
告诉客户端发送的内容类型
server.on('request', function (req, resp) {
//告诉对方我发送的数据类型是什么
resp.setHeader('Content-Type', 'text/plain; ');
resp.end("hello 小郭")
});
Content-Type 有哪些类型,表示哪些文件 www.runoob.com/http/http-c…
Content-Type 默认类型是什么?text/html
,会解析响应的html元素
如果是 text/plain
表示纯文本类型,默认不会解析html元素
发送网页
server.on('request', function (req, resp) {
if (req.url == '/') {
//发送html文件
fs.readFile("index.html", function (err, data) {
if (err) {
resp.setHeader('Content-Type', 'text/plain; charset=utf-8');
resp.end("文件不存在,请重试")
} else {
resp.setHeader('Content-Type', 'text/html; charset=utf-8');
resp.end(data)//参数可以是字符串也可以是Buffer,这里data是Buffer类型
}
});
}
});
发送图片
server.on('request', function (req, resp) {
if (req.url == '/') {
//告诉对方我发送的数据类型是什么
resp.setHeader('Content-Type', 'text/html; charset=utf-8');
resp.write("hello 小郭")
resp.write("");
resp.end()
} else if (req.url == '/img') {
//发送图片
resp.setHeader('Content-Type', 'image/jpeg;');//二进制文件(图片、音频)不需要指定编码
var rs = fs.createReadStream('5.jpg');
rs.once('close', function () {
resp.end()//真正关闭resp写入
});
rs.on('data', function (data) {
resp.write(data)
});
//resp.end()异步操作,出错!Error [ERR_STREAM_WRITE_AFTER_END]: write after end
}
});
踩坑记录:node http fs.createReadStrem 发送文件 Error ERR_STREAM_WRITE_AFTER_END]: write after end_Engure-CSDN博客
关于设置 Content-Type:
不同类型:
类型
Content-Type
纯文本 .txt
text/plain; charset=utf-8
html, htm
text/plain; charset=utf-8
.xml
text/xml
.jpg
image/jpeg
.png
image/png
.gif
image/gif
json格式
application/json
.pdf
application/pdf
.word
application/msword
编码类型:
- 对于二进制数据,不需要设置 charset
- 对于文本类型数据 text/* ,需要设置 charset
链接
node中文文档 nodejs.cn/
李立超Node.js(部分)www.bilibili.com/video/BV1bs…
服务器开发 - 黑马 www.bilibili.com/video/BV1Ns…