Node.js 简介
- 什么是Node.js
Node.js是一个基于 ChromeV8 引擎的javascript 运行环境。
Node.js 官网地址: https://nodejs.org/zh-cn/
- Node.js中javacript运行环境
基于v8 引擎 -通过–内置api (fs,path,http,js内置对象,querystring,etc…)----
执行待执行的javacript代码
1)浏览器是javascript的前端运行环境
2)Node.js是javascript后端运行环境
3)Node.js中无法调用DOM和BOM等浏览器内置api
- Node.js可以做什么
Node.js 作为一个javacript的运行环境,仅仅提供了基础的功能和api。然而,基于Node.js提供的这些基础功能,很多强大的工具
和框架层出不穷,学会Node.js可以让前端程序员胜任更多的工作和岗位。
1)基于 Express框架(http://www.expressjs.com.cn/),可以快速构建web应用
2)基于 Electron 框架(https://electronjs.org/) 可以构建跨平台的桌面应用
3)基于 restify框架(http://restify.com/) 可以快速构建api接口项目
4)读写和操作数据库、创建实用的命令工具辅助前端开发、etc…
总之:学了Node.js你比别人更能卷了!!!!!
-
如何学习Node.js
Node.js学习路径:
javaScript 基础语法 + Node.js内置模块(fs,path,http等)+第三方api模块(express,mysql)等 -
Node.js环境的安装
如果希望通过Node.js来运行javascript代码,则必须再计算机上安装Node.js环境才行
安装包从Node.js官网首页直接下载,进入到Node.js的官网首页(https://nodejs.org/en/)点击绿色的按钮,下载所需的版本后,双击直接安装即可
1)区分 LTS版本和Current版本的不同
1- LTS为长期稳定版本,对于追求稳定性的企业级项目来说,推荐安装LTS版本的Node.js
2- Current为新特性尝鲜版,对于热衷尝试新特性的用户来说,推荐安装Current版本的Node.js.但是,current版本中可能存在隐藏的Bug或者安全漏洞,因此不推荐在企业级项目中使用Current版本的Node.js.
2)查看 已经安装的Node.js版本号
win+r 输入 cmd
打开终端 输入 node --version 或者 node -v ,如果能看到版本号则安装成功。
3)什么是终端
专门为开发人员设计的,用于实现人机交互的一种方式.
常用命令 cls/clear 清空 cd 文件路径 cd …/ 返回上一级
4)node执行js代码
在终端输入 node js文件 就可以执行,一定要切换到js文件所在目录
5)终端快捷键
箭头↑ 定位到上一条命令
使用tab可补全文件路径
esc可以清空当前输入的命令
输入cls+回车 清空当前终端
fs文件系统 模块
fs模块是Node.js官方提供的用来操作文件的模块,它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
fs.readFlile() 读取指定文件中的内容
fs.writeFile() 向指定的文件中写入内容
需要先导入fs模块
读取
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname, './file/01.txt'), 'utf-8', (err, res) => {
console.log(__dirname)
if (err) {
console.log('读取失败');
} else {
console.log('读取成功,返回结果:' + res);
}
})
写入
const fs = require('fs')
fs.writeFile('./file/01.txt', '天气不错1111111111111', function(err) {
//如果写入失败 则err是个错误对象,如果成功err = null
if (err) {
console.log('写入失败');
} else {
console.log('写入成功!!!');
}
})
- fs模块路径动态拼接问题
在使用fs模块执行操作文件时,如果提供的操作路径是以 ./ 或者…/开头的相对路径时,很容易出现路径动态拼接错误的问题。
原因:代码在运行时,会执行node命令所处的目录,动态拼接出被操作文件的完整路径
解决方法:
1.提供文件的完整路径(不推荐,移植性差,不利于维护)
2.使用__dirname(注意是双下划线dirname) 表示当前文件所处的目录
path 路径模块
path模块是Node.js官方提供的,用来处理路径的模块,它提供了一系列的方法和属性,用来满足用户对路径的处理和需求
path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串
path.join(__dirname,pathStr)
path.basename()方法 用来从路径字符串中,将文件名解析出来
path.basename(fpath) //拿到文件名+扩展名
path.basename(fpath,’.html’) //传第二个参数可以只获取文件名
path.extname() 获取文件的扩展名
如果要使用则需要导入:
cosnt path = requrie(‘path’)
http 模块
- 什么是客户端,什么是服务器
在网络节点中,负责消费资源的电脑叫做客户端,负责对外提供网络资源的电脑叫做服务器。
http模块是Node.js 官方提供的、用来创建web服务器的模块。通过http模块提供的http.createServer()方法,就能方便
的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务
导入方式
cosnt http = require('http')
- 进一步理解http模块作用
服务器和普通电脑的区别在于,服务器上安装了web服务器软件,例如:IIS,Apache等。通过这些服务器软件,就能把一台普通电脑变成一台web服务器。
在node.js中我们不需要使用IIS,Apache等这些第三方web服务器软件。因为我们可以基于node.js提供的http模块,通过几行简单的代码,就能轻松的写一个服务器软件,从而对外提供web服务。
- 服务器相关概念
1)ip 地址
ip地址是互联网上每台计算机唯一地址,因此ip地址具有唯一性。如果把个人电脑比作电话,ip地址相当于电话号码。只有在知道对方ip地址的前提下,才能与对应的电脑之间进行数据通信。
2)ip地址的格式
通常使用 点分十进制 表示成 a.b.c.d 形式,其中a,b,c,d都是0~255之间的十进制整数。例如:用点分十进制表示的ip地址(192.168.1.1)
注意:
1–互联网中每台web服务器都有自己的ip地址,例如可以在windows终端中运行 ping www.baidu.com 命令查看到百度服务器的ip地址
2–在开发期间,自己的电脑就是一台服务器,也是一个客户端,为了方便测试,可以在自己的浏览器中输入 127.0.0.1这个ip地址,就能把自己的电脑当作一台服务器
进行访问了
3)域名和域名服务器
尽管ip地址能够唯一标记网络上的计算机,但是ip地址是一串上数字,不直观,不便于记忆,于是人们发明了另一套字符型的地址方案,即所谓的域名地址。
ip地址和域名是一一对应关系,这份对应关系存放在一种叫做域名服务器(DNS,Domain Name Sever)的电脑中,使用者只需通过好记得域名访问对应得服务器即可,对应得转换工作由域名服务器实现。因此,域名服务器就是提供ip地址和域名之间转换服务的服务器。
- 注意:
1.单纯使用ip地址,互联网中的电脑也能够正常工作。但有了域名的加持,能让互联网的世界变得更加方便。
2.在开发测试期间,127.0.0.1对应的域名是localhost,它们都代表我们自己这台电脑,在使用效果上没有任何区别。
4)端口号
计算机中的端口号,就好像现实生活中的门牌号一样。通过门牌号,外卖小哥可以准备把外卖送给你。
同理,一台电脑中可以运行很多个web服务,每个web服务对应一个唯一的端口号,客户端发送过来的网络请求,通过端口号,可以准确的交给对应的web服务进行处理
- 创建web服务器的基本步骤
//导入http模块
const http = require('http')
//创建web服务器实例
const server = http.createServer()
//为服务器实例绑定request事件
server.on('request', function(req, res) {
//req 是请求对象 ,它包含了与客户端相关的对象和属性 例如:
//req.url 是客户端请求的 url地址
//req.method 是客户端的method请求类型
console.log('someone visit server')
})
//4启动服务器
server.listen(80, function() {
console.log('sever running at http://127.0.0.1:80')
})
根据不同url响应不同页面
//导入http模块
const http = require('http')
//创建服务器实例
const server = http.createServer();
//监听服务器request请求 事件
server.on('request', (req, res) => {
console.log('some visit server')
// console.log(`请求的url地址是${req.url},请求的方法是${req.method}`)
const url = req.url;
const method = req.method;
const str = `请求的url地址是${url},请求的方法是${method}`
let content = '404'
if (url === '/' || url === '/index.html') {
content = '首页'
} else if (url === '/about.html') {
content = '关于'
}
//设置res的响应头 解决中文乱码
res.setHeader('Content-Type', 'text/html; charset=utf-8')
//调用res.end方法向客户端响应一些内容
res.end(content)
})
//启动服务器
server.listen(80, function() {
console.log('server running at http://127.0.0.1')
})
模块化
- 什么是模块化
在编程领域,就是遵守固定的规则,把一个大文件拆成独立并且互相依赖的多个小模块
模块化好处:
1)提高代码的复用性
2)提高代码的可维护性
3)实现按需加载
- 模块化规范
模块化规范就是对代码进行模块化拆分与组合时,需要遵守的那些规则
例如:
使用什么语法格式来引用模块
在模块中使用什么样的语法格式向外暴露成员
模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大的方便了各个模块之间的相互调用,利人利己。
- 模块分类
内置模块 例如 fs path http 由node.js提供
自定义模块 用户创建的每个js文件,都是自定义模块
第三方模块 由第三方开发出来的模块 并非官方提供的内置模块 也不是用户创建的自定义模块,使用前需要下载
1)加载模块 使用require() 会执行自定义模块里的代码,可以省略后面的.js
const m1 = require('./06自定义模块.js')
const m1 = require('./06自定义模块')
console.log(m1) //因为06没有暴露 所以返回一个空对象
2)模块作用域 ,每个模块只能访问模块内的变量,解决全局变量污染的问题
const m2 = require('./07模块化的作用域')
console.log(m2.name); //undefined
3)向外共享模块作用域中的成员
module对象
在每个js自定义模块中都有一个module对象,它里面存储了和当前模块相关的信息
console.log(module);
Module {
id: '.',
path: 'E:\\学习\\a桌面资料(图片画稿个人资料\\webStudy\\study\\2022nodejs',
exports: {},
parent: null,
filename: 'E:\\学习\\a桌面资料(图片画稿个人资料\\webStudy\\study\\2022nodejs\\08module.js',
loaded: false,
children: [],
paths: [
'E:\\学习\\a桌面资料(图片画稿个人资料\\webStudy\\study\\2022nodejs\\node_modules',
'E:\\学习\\a桌面资料(图片画稿个人资料\\webStudy\\study\\node_modules',
'E:\\学习\\a桌面资料(图片画稿个人资料\\webStudy\\node_modules',
'E:\\学习\\a桌面资料(图片画稿个人资料\\node_modules',
'E:\\学习\\node_modules',
'E:\\node_modules'
]
}
4)module.exports 与 exports
这两个作用相等,但主要最终以module.exports指向的为准
module.exports.username = 'zs'
module.exports.sayHello = function() {
console.log('hello')
}
const age = 20
module.exports.age = age
//exports 相当于 module.exports,最终于还是以module.exports指向的对象为准
exports.sex = '女'
npm 与 包
- 什么是包
包是第三方的模块,第三方开发的,免费试用
包是基于内置模块封装出来的,提供了更高级、更方便的API,极大的提高了开发效率
从哪里下载包 https://www.npmjs.com/ npm,inc公司
安装包 npm install 包名 或者 npm i 包名
安装指定版本的包 npm i 包名@版本号
包的语义化版本规范 包的版本号是以“点分十进制" 形式进行定义 总共有三位数字 例如 2.24.0
第一位数字 : 大版本
第二位数字: 功能版本
第三位数字: bug修复版本
- 包管理配置文件
npm规定,在项目根目录中,必须提供一个叫做package.json的包管理配置文件。用来记录与项目相关的一些配置信息。例如:
项目的名称、版本号、描述等
项目中都用到了哪些包
哪些包只在开发期间会用到
哪些包在开发和部署时都要用到
nodemodule 可以删除,便于团队之间共享代码,只需要记录在package.json文件中
快速创建 package.json 命令 npm init -y (只需要执行一次,目录需要英文)
一次性下载所有的包 ,当项目中没有包时候,执行 npm install 会一次性下载dependencies里面所有的包
卸载包 npm uninstall moment 没有简写 会自动从dependencies里面移除
- devDependencies节点
如果某些包只在项目开发阶段会用到,在项目上线后不会用到,则建议把这些包记录到devDependencies节点中
与之对应的如果某些包在开发和项目上线之后都要用到,则建议把这些包记录到dependencies节点中
npm i 包名 -D 安装到devDependencies中
上面的完整写法npm install 包名 --save-dev
实例:
//定义格式化时间的方法
function dateFormat() {
const date = new Date()
const yyy = date.getFullYear()
const mmm = padZero(date.getMonth() + 1)
const ddd = padZero(date.getDay())
const h = padZero(date.getHours())
const m = padZero(date.getMinutes())
const s = padZero(date.getSeconds())
return `${yyy}年${mmm}月${ddd}日 ${h}:${m}:${s}`
}
//补0的函数
function padZero(n) {
return n > 9 ? n : '0' + n
}
module.exports = {
dateFormat
}
----------------分割线 以下是另一个js文件
const df = require('./11定义格式化时间的方法')
const dt = new Date()
const dt2 = df.dateFormat()
console.log(dt2)
实例2使用moment包
const moment = require('moment')
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)
// 安装包 npm install 包名 或者 npm i 包名
//安装指定版本的包 npm i 包名@版本号
//包的语义化版本规范 包的版本号是以“点分十进制" 形式进行定义 总共有三位数字 例如 2.24.0
//第一位数字 : 大版本
//第二位数字: 功能版本
// 第三位数字: bug修复版本
解决包下载速度慢的问题
切换. npm的下包镜像源
下包的镜像源,指的就是下包的服务器地址
-
查看当前的下包镜像源
npm config get registry -
将下包的镜像源切换为淘宝镜像源
npm config set registry= https://registry.npm.taobao.org/ -
检查镜像源是否成功
npm config get registry
nrm 通过nrm包管理器,将nrm安装为全局可用的工具
npm i nrm -g
查看所有的可用镜像源
nrm ls
将下包的镜像源切换为taobao 镜像
nrm use taobao
包的分类规范以及包结构
- 项目包
那些被安装到项目的 node_modules目录中的包都是项目包
项目包又分为两类,分别是:
开发依赖包 (被记录到devDepencies节点中的包,只在开发期间会用到)
核心依赖包 (被记录到dependencies节点中的包,在开发期间和项目上线后都会用到)
- 全局包
在执行npm install 命令时,如果提供了-g 参数,则会把包安装成全局包
全局包会被安装到C:\users\用户目录\AppData\Roaming\npm\node_modules 目录下
npm i 包名 -g #全局安装指定的包
npm uninstall 包名 -g #卸载全局安装的包
只有工具性质的包,才有安装全局的必要性。因为它们提供了好用的终端命令。
判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明即可。
i5ting_toc
i5ting_toc 是一个可以把md文档转为html页面的小工具,使用步骤如下:
将 i5ting_toc 安装为全局包
npm install -g i5ting_toc
调用 i5sting_toc 轻松实现 md 转html 的功能
i5sting_toc -f 要转换的md文件路径 -o
规范的包结构
清楚了包的概念、以及如何下载和包之后,深入了解一下包的内部结构。
一个规范的包,他的组成结构,必须符合一下3点要求:
- 包必须以单独的目录而存在
- 包的顶级目录下必须要包含package.json这个包管理配置文件
- package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口。
可以通过 npm init -y 自动生成pakage.json文件
例如:
{
"name": "itheima-tools-icy",
"version": "1.0.0",
"description": "输入下班时间可根据当前时间计算出距离的下班时间并格式化,2022/3/23学习黑马nodejs,加油!",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["itheima", "dataFormat", "countLeveTime", "icy"],
"author": "icyakuya",
"license": "ISC"
}
此外,包含一个main入口文件,一个README.md介绍包的使用
main里的功能可独立抽离成js文件放在新建的src文件
如下图
发布包 和初始化包结构
登陆
npm login
输入账号密码邮箱 以及动态密码
发布
切换到包根目录下 npm publish
删除发布
npm unpublish 包名 --force
只能删除 72小时以内发布的包 ,否则永远无法删除
npm unpublish 删除的包 。在24小时内不允许重复发布
尽量发布有意义的包,没有意义的就删了
模块的加载机制
优先从缓存中加载
模块在第一次加载后会被存入缓存,也就意味着多次调用 require()不会导致模块代码执行多次
注意:无论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
-
内置模块的加载机制
内置模块时由Node.js官方提供的模块,内置模块的加载优先级最高。
例如,require(‘fs’)始终返回内置的fs模块,即使在node_modules目录下有名字像相同的包也叫做fs -
自定义模块的加载机制
使用 require 加载自定模块式,必须使用 ./ 或者 …/ 开头的路径标识符,否则会被当成第三方模块或者内置模块加载。会报错
如果省略了扩展名 按一下顺序加载
1.按照确切的文件名进行加载 2.补全js扩展名加载 3.补全.json扩展名加载 4.补全.node 扩展名加载
如果都加载失败了,则终端会报错。 -
第三方模块的加载机制
如果传递给 require()的模块标识符不是一个内置模块,也没有以 ./ 或者 …/ 开头 则node.js会从当前模块的父目录开始。尝试从/node_modules文件夹加载第三方模块
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录
注意只能找到盘符目录下例如 C:\ -
目录作为模块
把当前目录作为模块标识符,传递给require() 进行加载的时候,有三种加载方式:
1.在被加载的目录下查找一个叫做pakage.json的文件,并寻找main属性,作为require() 加载的入口
2.如果目录里没头pakage.json文件,或者main入口不存在或无法解析,则Node.js会试图加载目录下的index.js文件
3.如果以上两步都失败了,则Node.js会在终端打印错误消息,报告模块的缺失:Error.cannot find module 'xxx