【NodeJs】基础知识

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特点:

  1. 单线程
  • 在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。
  • Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
  1. 非阻塞I/O(异步I/O)
  • 当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。
  • 由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
  • 当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
  • 阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。
  • 这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。
  1. 事件驱动
  • 在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环境

  1. 下载地址https://nodejs.org/en/
  • LTS 版本:Long-term Support 版本,长期支持版,即稳定版。
  • Current 版本:Latest Features 版本,最新版本,新特性会在该版本中最先加入。
  1. 启动程序 node-v14.16.0-x64.msi 一直点 下一步…
  2. 在cmd中,输入 node -v 能查看版本号,node内置了npm,通过 npm -v 查看版本号
  3. 部分电脑要重启,系统环境变量才会起作用
  • 就是在系统的任何目录下,都能运行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代码部署上的很多问题,常见的使用场景有以下几种:
  1. 允许用户从NPM服务器下载别人编写的第三方包到本地使用
  2. 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用
  3. 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用

NPM常用命令:

  1. 命令:npm init 初始化生成 package.json 配置文件
    “jquery”: “^3.x.x” 这个^表示锁定大版本号为3,次版本和小版本安装最新的
    “jquery”: “~3.5.x” 这个~表示锁定大版本号为3,次版本号为5,小版本安装最新的
    “jquery”: “3.5.1” 表示安装固定的版本号

  2. 命令:npm init --yes 跳过所有提问生成默认的配置文件 -y

  3. 命令:npm install 包名npm i 包名 本地安装依赖包(当前项目能使用)默认-save
    下载安装包并更新package.json和package.lock.json文件

  4. 命令:npm install --global 包名npm i -g 包名 全局安装依赖包(所有项目都能使用)

  5. 命令:npm install -save 包名npm i -S 包名 安装项目依赖包(添加到dependencies字段)等价于本地安装 npm install 包名

  6. 命令:npm install -save-dev 包名npm i -D 包名 安装开发依赖包(添加到devDependencies字段)

  7. 命令:npm install 安装所有依赖包

  8. 命令:npm uninstall -save 包名 移除项目依赖模块

  9. 命令:npm uninstall -save-dev 包名 移除开发依赖模块

  10. 命令:npm cache clean 清除缓存数据

  11. 命令:npm list -g 查看所有全局安装的包

  12. 命令:npm list 包名 查看某个包的版本号

  13. 命令:npm update 包名 更新某个包的版本 只能更新小版本例如;(2.1.4~2.2.4)不能(^2.1.4 ~ ^3.1.6)

  14. 命令: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的一些缺陷而出现的:
  1. npm5之前,npm install的时候安装很慢,特别是新项目安装要等半天…
  2. 多人开发同一个项目时,安装的版本不一致会导致一些BUG出现(没有lock锁定文件)…

yarn常用命令:

  1. 命令:npm install yarn -g 使用npm全局安装yarn

  2. 命令:yarn -v 查看yarn的版本号

  3. 命令:yarn init 初始化生成 package.json 配置文件

  4. 命令:yarn init --yes 跳过所有提问生成默认的配置文件 -y

  5. 命令:yarn add 包名 安装某个项目依赖包,默认–save

  6. 命令:yarn add 包名 --dev 安装某个开发依赖包 -D

  7. 命令:yarn install 安装所有依赖包

  8. 命令:yarn remove 包名 删除项目依赖包,默认–save

  9. 命令:yarn remove 包名 --dev 删除开发依赖包

  10. 命令:yarn cache clean 清除缓存数据

  11. 命令:yarn upgrade 包名 更新某个包

  12. 命令: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代码的两种方式:
  1. 在window命令行环境中输入指令node并回车,进入node的交互式环境。
  • node交互式环境也称之为REPL(Read Eval Print Loop-读取评估打印循环),按两次 ctrl+c 可退出REPL环境。
  • 先输入 node 再回车,进入node的交互式环境,再输入js代码回车执行
  1. 把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文件就是一个模块,模块拥有自己独立的作用域,类、方法、变量等,对其他的模块都不可见
  1. 内置模块,安装nodejs时自带的模块,直接导入使用
  2. 第三方模块,别人写好的模块,下载后导入使用
  3. 自定义模块,自己写的功能模块,直接导入使用

内置模块

  • http模块,用于创建http服务器与http客户端
  • url模块,用于处理与解析 URL
  • fs模块,用于文件系统进行交互的API(file system -> fs)
  • path模块,用于处理文件路径和目录路径的实用工具
  • querystring 模块,用于解析和格式化URL查询字符串的实用工具
  • 。。。。。。

CommonJS模块化规范

  1. node应用由N多模块组成,采用的commonjs模块化规范
    2 CommonJS模块的特点:
  • 所有代码都运行在模块作用域,不会污染全局作用域
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果
  • 加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作
  • 模块加载的顺序,按照其在代码中出现的顺序执行
  1. module对象
  • CommonJS规范规定,每个模块内部,module变量代表当前模块
  • 这个变量是一个对象,它的exports属性(即module.exports)是对外的接口
  • module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports的值
  • 例如:module.exports = function(x){console.log(x);}
  1. 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)}
  1. 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)
  1. 读文件: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)
  1. 写文件: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 两个函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DomCode

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值