Node.js
- 官网:https://nodejs.org/en/
- 中文:http://nodejs.cn/
- 社区:https://cnodejs.org/
一、Node.js简介
- node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
- node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
- 简单的说 Node.js 就是运行在服务端的 JavaScript。
- V8引擎本身就是用于Chrome浏览器的JS引擎部分,但是Ryan Dahl这哥们,把这个V8搬到了服务器上,用于做服务器的软件。
- node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触角伸到了服务器端。与PHP、JSP、.net等相比(PHP、JSP、.net都需要运行在服务器程序上,Apache、Nginx、Tomcat、IIS。),Node.js跳过了Apache、Naginx、Tomcat、IIS等HTTP服务器,它自己不用建设在任何服务器软件之上。
- node.js是服务端的程序,写的js代码,都将运行在服务器上!
Node.js特点:
- 单线程
- 在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。
- Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
- 非阻塞I/O(异步I/O)
- 当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。
- 由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
- 当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
- 阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。
- 这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。
- 事件驱动
- 在Node中,客户端请求建立连接,提交数据等行为,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件循环”机制。
- Node.js底层是C++(V8引擎也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建。用事件驱动来完成服务器的任务调度,用一个线程,担负起了处理非常多的任务的使命。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vP1NJBn-1670602023382)(./imgs/02.png)]
Nodejs与传统服务端语言
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eujvXaS3-1670602023382)(./imgs/03.png)]
安装Nodejs
Node.js是一个让JavaScript运行在服务器端的开发平台,必须首先在本机安装Node.js环境
- 下载地址https://nodejs.org/en/
- LTS 版本:Long-term Support 版本,长期支持版,即稳定版。
- Current 版本:Latest Features 版本,最新版本,新特性会在该版本中最先加入。
- 启动程序 node-v14.16.0-x64.msi 一直点 下一步…
- 在cmd中,输入 node -v 能查看版本号,node内置了npm,通过 npm -v 查看版本号
- 部分电脑要重启,系统环境变量才会起作用
- 就是在系统的任何目录下,都能运行c:\program files\nodejs里面的程序
Windows系统CMD命令
- 打开方式:win + r 输入 cmd 回车
- 命令 c: 或 d: 或 e: 进入相应的磁盘
- 命令 mkdir xx 创建xx目录
- 命令 cd xx 进入xx文件夹
- 命令 cd … 返回上一级目录
- 命令 cd / 返回根目录
- 命令 echo.> xx.xx 创建xx文件(包含换行的文件)
- 命令 dir 查看当前目录下的全部文件
- 命令 del xx 删除xx文件
- 命令 cls 清屏
- 命令 exit 退出cmd窗口
- 命令 ipconfig 查看本机ip地址
( 需要添加系统环境变量Path “C:\Windows\System32” )
NPM 介绍
- 官网:https://www.npmjs.cn/
- NPM的全称是Node Package Manager,是一个NodeJS包管理工具
- NPM是随同NodeJS一起安装的
包管理工具,包的结构使你能够轻松跟踪依赖项和版本号 - NPM能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
- 允许用户从NPM服务器下载别人编写的第三方包到本地使用
- 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用
- 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用
NPM常用命令:
-
命令:
npm init初始化生成 package.json 配置文件
“jquery”: “^3.x.x” 这个^表示锁定大版本号为3,次版本和小版本安装最新的
“jquery”: “~3.5.x” 这个~表示锁定大版本号为3,次版本号为5,小版本安装最新的
“jquery”: “3.5.1” 表示安装固定的版本号 -
命令:
npm init --yes跳过所有提问生成默认的配置文件 -y -
命令:
npm install 包名或npm i 包名本地安装依赖包(当前项目能使用)默认-save
下载安装包并更新package.json和package.lock.json文件 -
命令:
npm install --global 包名或npm i -g 包名全局安装依赖包(所有项目都能使用) -
命令:
npm install -save 包名或npm i -S 包名安装项目依赖包(添加到dependencies字段)等价于本地安装npm install 包名 -
命令:
npm install -save-dev 包名或npm i -D 包名安装开发依赖包(添加到devDependencies字段) -
命令:
npm install安装所有依赖包 -
命令:
npm uninstall -save 包名移除项目依赖模块 -
命令:
npm uninstall -save-dev 包名移除开发依赖模块 -
命令:
npm cache clean清除缓存数据 -
命令:
npm list -g查看所有全局安装的包 -
命令:
npm list 包名查看某个包的版本号 -
命令:
npm update 包名更新某个包的版本 只能更新小版本例如;(2.1.4~2.2.4)不能(^2.1.4 ~ ^3.1.6) -
命令:
npm run xxx用来执行在 package.json 中 scripts 属性下定义的脚本
- “scripts” 字段定义脚本命令
- “start”: “node test.js”
- 命令:
npm run start等同于直接执行node test.js
yarn介绍
- 官网:https://yarnpkg.com/
- Yarn是由Facebook、Google等联合推出的一个新的包管理工具
- Yarn是为了弥补npm的一些缺陷而出现的:
- npm5之前,npm install的时候安装很慢,特别是新项目安装要等半天…
- 多人开发同一个项目时,安装的版本不一致会导致一些BUG出现(没有lock锁定文件)…
yarn常用命令:
-
命令:
npm install yarn -g使用npm全局安装yarn -
命令:
yarn -v查看yarn的版本号 -
命令:
yarn init初始化生成 package.json 配置文件 -
命令:
yarn init --yes跳过所有提问生成默认的配置文件 -y -
命令:
yarn add 包名安装某个项目依赖包,默认–save -
命令:
yarn add 包名 --dev安装某个开发依赖包 -D -
命令:
yarn install安装所有依赖包 -
命令:
yarn remove 包名删除项目依赖包,默认–save -
命令:
yarn remove 包名 --dev删除开发依赖包 -
命令:
yarn cache clean清除缓存数据 -
命令:
yarn upgrade 包名更新某个包 -
命令:
yarn run xxx用来执行在 package.json 中 scripts 属性下定义的脚本
- “scripts” 字段定义脚本命令
- “start”: “node test.js”
- 命令:
yarn run start等同于直接执行node test.js
淘宝镜像:
-
命令:
npm config get registry查看npm源地址 -
默认源:https://registry.npmjs.org/
-
命令:
npm config set registry https://registry.npm.taobao.org修改npm源地址 -
命令:
yarn config get registry查看yarn源地址 -
默认源:https://registry.yarnpkg.com
-
命令:
yarn config set registry https://registry.npm.taobao.org修改yarn源地址 -
命令:
npm install -g cnpm --registry=https://registry.npm.taobao.org安装使用cnpm
编写Nodejs程序
- 之前所编写的javascript代码都是在浏览器中运行的,现在我们编写的javascrip代码都是在Node环境中执行
- 在nodejs中执行js代码的两种方式:
- 在window命令行环境中输入指令node并回车,进入node的交互式环境。
- node交互式环境也称之为REPL(Read Eval Print Loop-读取评估打印循环),按两次 ctrl+c 可退出REPL环境。
- 先输入
node再回车,进入node的交互式环境,再输入js代码回车执行
- 把javascript代码写在后缀为.js的文件中,如 hello.js 文件,在window命令行中输入
node hello.js即可执行
- 在hello.js中编写代码:var a = 2; var b = 2; console.log(a+b);
- 命令行中执行:
node hello.js运行hello.js中的代码
注:在浏览器环境中全局对象是window,在node环境中全局对象变为global
模块化
- 每一个js文件就是一个模块,模块拥有自己独立的作用域,类、方法、变量等,对其他的模块都不可见
- 内置模块,安装nodejs时自带的模块,直接导入使用
- 第三方模块,别人写好的模块,下载后导入使用
- 自定义模块,自己写的功能模块,直接导入使用
内置模块
- http模块,用于创建http服务器与http客户端
- url模块,用于处理与解析 URL
- fs模块,用于文件系统进行交互的API(file system -> fs)
- path模块,用于处理文件路径和目录路径的实用工具
- querystring 模块,用于解析和格式化URL查询字符串的实用工具
- 。。。。。。
CommonJS模块化规范
- node应用由N多模块组成,采用的commonjs模块化规范
2 CommonJS模块的特点:
- 所有代码都运行在模块作用域,不会污染全局作用域
- 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果
- 加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作
- 模块加载的顺序,按照其在代码中出现的顺序执行
- module对象
- CommonJS规范规定,每个模块内部,module变量代表当前模块
- 这个变量是一个对象,它的exports属性(即module.exports)是对外的接口
- module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports的值
- 例如:
module.exports = function(x){console.log(x);}
- exports对象
- node为每一个模块提供了一个exports变量(对象),指向 module.exports
- 这相当于每个模块中都声明了
var exports = module.exports - 这样,在对外输出时,可以在这个变量上添加方法
- 例如:
exports.add = function (r){return Math.PI * r * r} - 注意:不能给exports直接赋值,这样就切断了exports和module.exports的关系
- 例如:
exports = function(x){console.log(x)}
- require方法
- require方法用于加载模块文件,相当于读入并执行一个js文件,可以省略.js
- require(‘包名’)会加载执行某个包的入口文件,默认是index.js
- 在commonjs模块规范中,加载某个模块,其实是加载该模块的 module.exports 属性
// 在 example.js 文件中
exports.name = 'tom'
exports.age = 50
// 在 demo.js 文件中
var m1 = require('./example.js')
console.log( m1.name ) // tom
console.log( m1.age ) // 50
// 或者 example.js 文件中
var name = 'tom'
function fn(){console.log(1)}
module.exports = {fn:fn, name:name}
// module.exports = {fn,name}
// ES6中对象的 key 和 value 一致时,可以简写:{hehe,haha}
// 在 demo.js 文件中
var m1 = require('./example.js')
console.log( m1.name ) // 'tom'
m1.fn() // 1
常用内置模块
内置模块为安装nodejs时自带的模块,可以直接使用
http 模块
- 可用于创建http服务器与http客户端
- 搭建web服务:
var http = require('http')// 加载http模块
var server = http.createServer()// 创建http服务
server.on('request', callback)// request事件,用于监听来自客户端的请求
server.listen(port, host, callback)// 启动http服务,监听host端口
注意:
- 在监听request事件中,最后一定要res.end()结束响应;
- 浏览器显示中文可能是乱码,需设置响应头告诉浏览器显示时所使用的编码,在res.end()之前设置响应头、状态码、响应内容类型及编码
res.setHeader("Content-Type","text/plain;charset=utf-8")//响应纯文本
res.setHeader("Content-Type","text/html;charset=utf-8")//响应html文本
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})//响应html文本
Content-Type:用于定义用户的浏览器如何处理将要加载的数据
text/html 表示响应内容为html的形式,浏览器对响应内容按html解析
text/css 表示响应内容为css的形式,浏览器对响应内容按css解析
text/plain 表示响应内容为纯文本的形式,浏览器不会对其进行其它处理
application/json 表示响应内容为序列化后的 JSON 字符串
// 加载模块
let http = require('http')
// 创建服务
let server = http.createServer()
// 监听request事件
server.on('request',(req,res)=>{
// 当前端有用户请求进来时触发request事件
// req -> request 请求对象
// res -> response 响应对象
console.log('有用户请求进来了。。。')
// 设置响应头消息
res.setHeader('Content-Type','text/plain;charset=utf-8')
// 结束响应,并给前端响应内容
res.end('hello,你好')
})
// 启动服务(端口号,主机,回调函数)
server.listen(3000,'localhost',()=>{
console.log('服务器启动成功,访问:http://localhost:3000')
})
插件
-
自动重启服务器:
-
安装:
npm install --global nodemon -
之前使用:
node xxx.js现在改成:nodemon xxx.js -
本地服务器
-
npm i http-server -g
-
cmd 进入当前目录 运行 http-server
url 模块
- url模块用于处理与解析 URL
const url = require('url')// 加载url模块
let urlStr = 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head';
// url.parse()方法 将url字符串转成对象
let urlObj = url.parse( urlStr ) // 默认false,query为字符串
let urlObj = url.parse(urlStr,true) // 设置true,query为对象
console.log( urlObj ) // 如下o_url对象
let o_url = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.baidu.com',
port: null,
hostname: 'www.baidu.com',
hash: '#head',
search: '?wd=directory&spt=123&issp=888',
// query: 'wd=directory&spt=123&issp=888',
query: { wd: 'directory', spt: '123', issp: '888' },
pathname: '/ss/abc',
path: '/ss/abc?wd=directory&spt=123&issp=888',
href: 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head'
}
// url.format()方法 将url对象转成字符串
let s_url = url.format( o_url )
console.log( s_url )
// 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head'
fs 模块
- fs模块提供了用于与文件系统进行交互的API(file system -> fs)
- 读文件:fs.readFile(file[, options], callback)
- 参数1:要读取的文件路径,必填。
- 参数2:读取文件时的选项,比如:文件编码utf8。选填。
- 参数3:文件读取完毕后的回调函数,必填。
- 注意:
- 该操作采用异步执行
- 回调函数有两个参数,分别是err和data(默认是Buffer 二进制数据流)
- 如不指定编码,返回二进制数据流,如指定编码utf8,会返回指定的编码数据
- 异步操作,回调函数第一个参数是错误对象err(错误的回调优先),默认是null
// 加载模块
let fs = require('fs')
// 异步读文件
console.log(11111)
fs.readFile('./test.txt','utf8',(err,data)=>{
// err 错误对象,读取失败时是一个对象,读取成功时是null
// data 读取到的数据
if (err) {
console.log('文件读取失败:'+err)
} else {
console.log('文件读取成功:'+data)
}
})
console.log(22222)
// 同步读取文件
console.log(11111)
let data = fs.readFileSync('./test.txt','utf8')
console.log(data)
console.log(222222)
- 写文件:fs.writeFile(file, data[, options], callback);
- 参数1:要写入的文件路径,必填。
- 参数2:要写入的数据,必填。
- 参数3:写入文件时的选项,比如:文件编码。
- 参数4:文件写入完毕后的回调函数,必填。
- 注意:
- 该操作采用异步执行
- 如果文件存在则替换原内容
- 默认写入的文件编码为utf8
- 回调函数有1个参数:err,表示在写入文件的操作过程中是否出错了。
- 如果出错了err != null,成功时 err === null
- 写入文件(文件不存在则自动创建)
- writeFile 写入文件是先把文件内容清空再写入
- appendFile 在内容后面追加写入
// 加载模块
let fs = require('fs')
// 写文件(覆盖原来的内容)
fs.writeFile('./test.txt','12345678',(err)=>{
if (err) {
res.end('error')
} else {
res.end('success')
}
})
// 写文件(追加内容)
let data = '末尾追加内容2'
fs.appendFile('./test.txt',data,(err)=>{
if (err) {
res.end('error')
} else {
res.end('success')
}
})
// 删除文件
fs.unlink('./abc.txt',(err)=>{
if (err) {
console.log('删除失败')
} else {
console.log('删除成功')
}
})
// 创建文件夹
fs.mkdir('./demo2',(err)=>{
if (err) {
console.log('创建失败')
} else {
console.log('创建成功')
}
})
// 读取文件夹
fs.readdir('./',(err,data)=>{
// fs.readdir('./demo',(err,data)=>{
if (err) {
console.log('读取失败')
} else {
console.log(data) // [ 'file1.js', 'file2.js', 'project' ]
}
});
// 删除文件夹(只能删除空文件夹)
fs.rmdir('./tao',(err)=>{
if (err) {
console.log('删除失败')
} else {
console.log('删除成功')
}
})
path 模块
- path模块提供用于处理文件路径和目录路径的实用工具
- path模块的默认操作会根据 Node.js 程序运行的操作系统而有所不同
- 如在 Windows 操作系统上时,path 模块会使用 Windows 风格的路径
// 加载模块
const path = require("path")
// path.join(path1[, path2]...) 返回拼接后的路径
// 将多个路径结合在一起,并转换为规范化路径
console.log(path.join('a', 'b/c', '/user')) // 'a\b\c\user'
console.log(path.join('/a', 'b/c', 'user')) // '\a\b\c\user'
console.log(path.join('./a', 'b/c', 'user/')) // 'a\b\c\user\'
// path.resolve([...paths]) 将一系列路径解析成绝对路径,从右到左解析
// 如果没有参数调用,返回当前工作路径
console.log(path.resolve())
// 'C:\Users\qf\Desktop\nodeDemo\day1'
// 多个path拼接时,字符串的起始位置都没有'/',则所有的字符串直接拼接
console.log(path.resolve('a','b','c'))
// 'C:\Users\qf\Desktop\nodeDemo\day1\a\b\c'
// 如果其中一个字符串的起始位置有'/',则不再向前拼接
console.log(path.resolve('a','/b','c')) // 'C:\b\c'
// ./ 与字符串起始位置没有任何东西时,是一致的情况
console.log(path.resolve('a','./b','c'))
// 'C:\Users\qf\Desktop\nodeDemo\day1\a\b\c'
// ../ 会跳过前面最近的一个字符串的拼接
console.log(path.resolve('a','../b','c'))
// 'C:\Users\qf\Desktop\nodeDemo\day1\b\c'
// path.basename(path[, ext]) 返回路径的最后部分(文件名)
// path目标路径,ext要截掉的内容
console.log(path.basename('/a/b/c/test.txt')) // test.txt
console.log(path.basename('/a/b/c/test.txt','.txt')) // test
console.log(path.basename('C:/test/aabb')) // aabb
// path.dirname(path) 与basename相对,返回除最后一部分的前面部分路径
console.log(path.dirname('/a/b/c/test.txt')) // '/a/b/c'
console.log(path.dirname('C:/test/aabb')) // 'C:/test'
querystring 模块
- querystring模块提供用于解析和格式化URL查询字符串的实用工具
// 加载模块
const qs = require('querystring')
// 将query字符串转成对象
let str = 'wd=directory&spt=123&issp=888'
let obj = qs.parse( str ) // 默认等价于 qs.parse( str, '&', '=' );
console.log( obj ) // { wd: 'directory', spt: '123', issp: '888' }
let str = 'wd-directory#spt-123#issp-888'
let obj = qs.parse( str, '#', '-' )
console.log( obj ) // { wd: 'directory', spt: '123', issp: '888' }
// 将对象转成query字符串
let obj = { wd: 'directory', spt: '123', issp: '888' }
let str = qs.stringify( obj )
console.log( str ) // 'wd=directory&spt=123&issp=888'
let obj = { wd: 'directory', spt: '123', issp: '888' }
let str = qs.stringify( obj, '@', '-' )
console.log( str ) // 'wd-directory@spt-123@issp-888'
// query字符串编码
let str = 'msg=你好&pw=123 456'
let res = qs.escape( str )
console.log( res ) // msg%3D%E4%BD%A0%E5%A5%BD%26pw%3D123%20456
// query字符串解码
res = qs.unescape( res )
console.log( res ) // 'msg=你好&pw=123 456'
全局变量
__dirname 表示当前执行的脚本所在目录的绝对路径
如:D:\phpstudy_pro\WWW\test\GP03\day33
__filename 表示当前执行的脚本文件的绝对路径
如:D:\phpstudy_pro\WWW\test\GP03\day33\test.js
process是一个全局进程模块
console.log( process.env ) 当前的环境信息
console.log( process.argv[2] ) 获取输入的命令
Error对象
let err = new Error(‘发送错误了’);
console.log(err); 这只是一个错误对象,不会终止代码执行
throw err; 抛出错误,会终止代码执行
console.log(‘这里不会执行’)
练习
1. 理解消化今天所学内容
2. 相关练习代码自己敲一遍
3. 自己封装querystring.parse 和 querystring.stringify 两个函数
958

被折叠的 条评论
为什么被折叠?



