nodeJS笔记
node是什么
-
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
-
node是一个基于chromeV8引擎的JavaScript代码运行环境
-
安装完成后使用命令行工具
node --version
或者node -v
来查询当前安装node 的版本号
nodejs的组成
- JavaScript的组成部分
- ECMAscript
- 规定JavaScript的语法(核心)
- DOM和BOM
- 是浏览器这个运行环境为JavaScript去提供的API
- ECMAscript
- nodeJS
- ECMAscript
- node模块API
- 在浏览器中的全局对象为window;在Node中的全局对象是global
JavaScript开发的弊端
- JavaScript在使用时存在的两大问题:文件依赖和命名冲突。
- 文件依赖
- 文件中的相互引用并不能直观的看出
- 命名冲突
- 在文件中引入别的文件,则被引入文件对于当前的文件是完全可见的,也就是说被引入文件中的变量是可以被访问到的且可以被当前文件重新赋值
nodeJS中模块化开发规范
- nodejs规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数在默认情况下在外部是无法访问的
- 模块的内部可以使用
exports
对象进行成员的导出;使用require
导入其他模块exports.XXX = XXX
- 将需要导出的变量或者是函数赋值给exports对象的一个属性,其属性名可以自定义
require(route)
- 参数为导入文件的路径(文件的后缀可以省略)
- 该方法的返回值为导入文件中的exports对象
- 导出文件的另一种方式
module.exports.XXX = XXX
- exports是module.exports的别名(地址引用关系,导出对象最终以后者为准!)
- 注意!若导出的为一个对象,就意味着将exports的地址指向了别处
系统模块
-
也就是node运行环境提供的API,因为这些API都是以模块化的方式进行开发的,所以我们又称node运行环境提供的API为系统模块
-
系统模块fs(fileSystem)
-
导入模块
const fs = require('fs')
-
使用方法
readFile(route, [encoding], callback)
读取文件 -
由于在读取文件的时候并不能保证文件的读取在指定的时间完成,也就不能使用返回值的方式接收读取的结果,所以需要回调函数来处理
-
回调函数的参数:error和data也就是错误信息和读取的数据;若发生错误则error为一个错误对象否则为null,若读取成功则data为读取到的数据
-
使用方法
writeFile(route, data, callback)
写入数据-
由于在写入文件的时候并不能保证文件的读取在指定的时间完成,所以需要回调函数来处理
-
const content = '写入的数据';
fs.writeFile
(
'../index.html',
content,
function(error)
{
if(error)
{
console.log(error);
return;
}
console.log('文件写入完成!');
}
) -
-
-
系统模块path(路径操作模块)
- 在不同的系统中路径的分隔符是不一致的,所以需要进行路径的拼接
- 引入模块path
const paht = require('path')
- 使用方法
join(route1, route2, ···)
实现路径的拼接- 可以使用变量来接收拼接好的路径
- 可以使用
__dirname
来获取当前文件所在的路径
- require在引入文件时是相对于当前文件所在位置
-
npm(node package manager,node 的第三方包管理工具)
-
下载指定的包
npm install XXX
, 默认情况下,下载的包会保存在当前命令行的执行目录(创建的node_modules文件夹下面)- 全局安装
npm install -g
,一般用于安装一些命令行工具 - 本地安装
- 全局安装
-
删除指定的包
npm uninstall XXX
-
使用npm下载包时会生成一个node_modules文件夹,里面包含的时当前下载的包运行时所依赖的其他模块,npm为其提供了一个package.json的项目描述文件,该文件会记录当前的项目依赖了那些模块
- package.json文件介绍
- 该文件为项目描述文件,记录的当前项目的某些信息,可以使用
npm init -y
(-y为参数,也就是全部按照默认值)命令来初始化生成该文件
{ "name": "project1", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies":{ "formidable": "^1.2.1", "mime": "^2.3.1" }, "devDependencies":{ "gulp": "^3.9.1" } }
- main :主模块
- scripts :命令的别名(当某些命令过于长且十分繁琐时,可以命名为一个自定义命令来表示)
- 运行自定义命令
npm run XXX
- 运行自定义命令
- keywords :项目关键字
- author :作者
- license :项目遵从的协议
- dependencies :项目依赖模块版本及其版本号
- 当项目传递给别人时不需要将所依赖的库一起传递,只需将package.json文件一起传递即可,在接收到项目的时候在其根目录下使用
npm install
下载项目所依赖的文件即可
- 当项目传递给别人时不需要将所依赖的库一起传递,只需将package.json文件一起传递即可,在接收到项目的时候在其根目录下使用
- devDependencies: 开发依赖,在package.json中生成开发依赖文件目录只需要在下载开发依赖包时添加参数即可
npm XXX --save --dev
- 在接收到项目的时候仅下载项目运行依赖可以使用
npm install --production
- 在接收到项目的时候仅下载项目运行依赖可以使用
-
文件package-lock.json记录的包之间的依赖关系以及其相应的版本和下载地址等等
-
第三方模块
-
nodemon (命令行工具)
- 在nodejs中每次检测到指定文件被修改保存后将会重新执行该文件
- 使用时在命令行工具中使用nodemon替换node命令来执行文件
-
nrm(npm registry manager) (npm下载地址切换工具,命令行工具)
- npm默认的下载地址在国外,国内下载不稳定且网速较慢,国内的一些较大的公司建立的国外网站的镜像服务器
- 查询可用下载地址列表
nrm ls
- 切换下载地址
nrm use XXX
-
gulp(基于node平台开发的前端构建工具)
- 在项目根目录下建立gulpfile.js文件
- 重构项目的文件夹结构
- src目录存放源代码文件
- dist目录存放构建后的文件
- 在gulpfile.js中编写需要执行的任务
- gulp.src() :获取任务要处理的文件
- gulp.dest() :输出文件
- gulp.task() :建立任务
- gulp.watch() :监控文件的变化
- 在命令行中执行gulp任务
const gulp = require('gulp'); gulp.task ( 'task1', function() { console.log('任务开始执行'); gulp.src('./src/html/index.html').pipe( gulp.dest('./dist/html') ); } )
task()
方法中的参数为:任务名称和任务的回调函数- 若将回调函数替换为
[XXX, XXX, ···]
中括号内为任务名称,则在执行时会依次执行其中的各项任务 - 注意!处理文件的代码需要放在pipe方法中
- 若将回调函数替换为
- 执行gulp任务的命令行工具为gulp-cli,全局安装后在命令行工具中使用
gulp XXX
来调用指定的任务 - gulp可以实现的操作很少,主要时是依赖于各种插件来实现各种主要的操作
- 各种插件的使用需要参考插件的参考手册
nodejs中模块加载机制
- 若使用
require(XXX)
引入文件时省略文件的后缀会先查找匹配的js文件,若无匹配的文件则会匹配同名文件夹,若匹配到文件夹则会在文件夹中查找index.js文件,若为查找到index.js文件则会在当前文件夹中查找main选项中的入口文件,若没有查找到指定的入口文件或者没有指定入口文件,则判定模块未找到 - 当模块没有路径和后缀时,会将其当作系统模块查找,若没有查找到则会去node_modules文件夹下面去查找,之后的流程同省略文件后缀的查找规则
art-template模板引擎
该模块的作用是更加便捷高效的操作字符串
-
下载模块
npm install art-template
-
引入模块后得到的是一个实现拼接数据和模板的方法
const template = require(src, data)
,该方法的参数为模板的路径与提供的数据,格式为对象类型(一般模板都会存放在一个名为views的文件夹内)。该方法返回值为拼接好的字符串const template = require('art-template'); const path = require('path'); const src = path.join(__dirname, 'views', 'index.art'); const html = template ( src, { name: 'tom', age: 12, } ) console.log(html);
-
将模板中需要引入的数据使用双花括号括住,并填入对应的数据的键名
Document {{name}}
{{age}}
-
模板语法
-
分为标准语法与原始语法
- 标准依法可以让模板更容易读写
- 原始语法具有强大的逻辑处理能力
-
输出指定数据
- 标:
{{XXX}}
- 原:
<%= XXX %>
- 标:
-
其内部还可以做简单的运算
- {{ 1+1 }}
- <%= 1+2 %>
-
三目运算
- {{ (1+1=2) ? ok : no }}
- <%= (1+1=2) ? ok : no %>
-
若数据为html字符串,出于安全性的考虑,默认模板引擎将会输出字符串实体而不是html标签
- 若需要输出为html标签即可以使用{{@ XXX }}或者<%- XXX %>
-
条件判断
{{ if 判断条件 }} ··· {{ else if 判断条件 }} ··· {{ else if 判断条件 }} ··· ··· ··· {{ else }} ··· {{ /if }}
<% if(···){ %> ··· <% } else if(···) { %> ··· <% } else { %> ··· <% } %>
-
循环
{{each 循环数组}}
- {{$value.XXX}} // $value指的是当前循环的对象 {{$value.XXX}}
- {{/each}}
<% for(var i=0; i
<%= XXX[i].XXX %> <%= XXX[i].XXX %> <% } %> -
子模版的引入
{{ include 'src' }}
<% include('src') %>
-
模板继承
- 抽离模板
Document {{block 'head'}}{{/block}} // 使用block标记预留需要填充的位置,并标识名称 {{block 'content'}}{{/block}}- 引入并填充模板
{{ extend 'src' }} // 引入模板 {{block 'head'}} ··· {{/block}} // 填充内容
-
-
模板配置
-
导入模板变量
- 当我们需要在模板中处理某些数据或者其他内容时需要借助函数
- 导入模板变量
template.defaults.import.XXX = XXX
(变量名 = 变量值) - 导入后就可以在模板中直接使用该方法
-
配置模板根目录
- template.defaults.root = src(模板存储路径)
- 之后在渲染模板的时候仅在第一个参数内传入模板名称即可,渲染时会自动在模板根目录下寻找该模板
-
配置模板后缀
- template.defaults.extname = '.XXX'(模板后缀)
- 之后在渲染模板的时候就会为当前的模板自动添加模板后缀
-
express框架
express框架是一个基于Node平台的web应用开发框架
提供了方便简洁的路由定义方式
对获取HTTP请求参数进行了简化处理
对模板引擎支持度高方便动态渲染HTML页面
提供中间件机制有效的控制HTTP请求
拥有大量大三方中间件对功能进行扩展
-
创建网站服务器对象
const app = express();
-
响应请求
- get请求
- 使用send方法响应请求
- 自动检测响应内容类型
- 自动设置http状态码
- 自动设置响应内容类型和编码
- 使用send方法响应请求
app.get ( '/', // 请求路径 function(req,res) // 响应处理函数 { res.send('ok'); } )
- get请求
-
中间件
-
主要有两部分构成:中间键方法以及请求处理函数
-
中间键方法由express框架提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求
-
针对一个请求可以设置多个中间件来处理,但是在默认情况下请求由上到下依次匹配中间件,一旦匹配成功,终止匹配
-
可以调用next方法将请求的控制权交给下一个中间件,直到遇到请求结束的中间件
const express = require('express'); const app = express(); app.get ( '/zhong', function(req,res,next) { req.name = '第一个中间件内部的内容'; next(); //递交控制权 } ) app.get ( '/zhong', function(req,res,next) { res.send('ok' + req.name); } ) app.listen(3000, () => { console.log('网站服务器启动成功!'); });
-
app.use
- 不传入请求地址,将匹配所有请求方式,可以直接传入请求处理函数,接收所有请求
- 传入请求地址,将不考虑请求的方式直接接收这个请求
-
错误处理中间键
- 下面的方法仅能捕获到同步代码出错
- 异步代码出现错误需要手动抛出:next(错误对象)
const express = require('express'); const app = express(); app.get ( '/index', function(req,res) { throw new Error('程序遇到未知错误!') } ) app.use ( function(error,req,res,next) { res.status(500).send(error.message); } ) app.listen(3000, () => { console.log('网站服务器启动成功!'); });
-
捕获错误
-
try catch可以捕获异步函数以及其他代码在执行过程中的错误
try { ··· } catch(error) { ··· next(error); }
-
尝试执行try代码块中的内容,若发生错误将跳转到catch中的代码块中执行,这里将手动触发错误处理中间件;若没有错误发生,将跳过catch代码块中的内容继续向下执行
-
-
获取get请求参数
- get 请求参数在请求对象下的query属性中,且请求参数是处理好的对象类型
-
获取post请求参数
-
借助第三方包
body-Parser
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use( bodyParser.urlencoded({extended: false}) ); // 拦截所有请求 // extended属性为是否使用第三方模块(QS)处理请求参数 app.post ( '/index', function(req,res) { res.send( req.body ); // 使用请求对象下的body属性获取post请求参数 } ) app.listen(3000, () => { console.log('网站服务器启动成功!'); });
-
这里值得注意的是
app.use( bodyParser.urlencoded({extended: false}) );
传入的是一个方法,但是该方法有一个返回值就是一个请求处理函数app.use( fun1({mark: true}) ); function fun1(obj) { return function(req,res,next) { if(obj.mark) { console.log('yes'); next(); } else { console.log('no'); next(); } } }
-
-
构建模块化路由
-
实例
const express = require('express'); const app = express(); const home = express.Router(); // 创建路由对象 app.use('/home', home); // 匹配请求路径 home.get // 创建二级路由 ( '/index', function(req, res) { res.send('home/index'); } ) app.listen(3000, () => { console.log('网站服务器启动成功!'); });
-
模块化路由
const express = require('express'); const home = express.Router(); home.get( '/index', (req,res) => { res.send('首页'); } ); module.exports = home;
const express = require('express'); const app = express(); const home = require('./indexRouter.js'); app.use('/home', home); app.listen(3000, () => { console.log('网站服务器启动成功!'); });
路由参数
-
实例代码
app.get ( '/index/:id/:name/:age/···', // :id为占位符,也就是在请求index时必须指定id参数 function(req,res) { res.send(req.params); // 输出当前的参数(对象类型) } )
-
请求地址格式参照
http://localhost:3000/index/XXX/XXX···
静态资源托管
- Express框架中内置的静态资源托管方法
express.static('静态资源地址')
- 使用服务器对象下的use方法拦截所有的请求,并将静态资源托管方法传入
app.use(exprss.static('···'))
当请求地址为静态资源目录,就会直接将静态资源响应并终止当前的请求,若不是静态资源目录则调用next方法递交权限
Express框架中的模板引擎
- 模板引擎art-template在原有模板引擎的基础上进一步封装,以便于更好的配合express框架使用,封装后的模板引擎为express-art-template
- 语法并没有改变,但是在模板的配置上做了某些调整
- 指定相应的模板引擎渲染指定的模板
app.engine('模板后缀', require('express-art-template'))
- 设置模板所在路径
app.set('views', src)
- 设置默认后缀
app.set('view engine', 'art')
- 渲染模板
res.render('需要渲染的模板名称', {对应的数据})
- 响应对象中的render方法
- 拼接模板路径
- 拼接模板后缀
- 对应模板数据
- 将结果返回给客户端
- 响应对象中的render方法
- app.locals对象中的数据可以在所有模板中访问到