一、基础
运行环境搭建
LTS(Long Term Support) 稳定版
Current 实验版
下载页面:http://nodejs.cn/download/
命令行输入node -v,查看是否安装成功
JS由三部分组成:ECMAScript、DOM、BOM。
Node.js由ECMAScript及Node环境提供的一些附加API组成的,包括文件、网络、路径等等一些更加强大的API。
ECMAScript语法在Node环境中都可以使用
JS开发弊端
两大问题:文件依赖和命名冲突
Node.js模块化开发
Node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法得到。
模块内部可以使用exports对象进行成员导出,使用require方法导入其他模块。
模块成员导出
exports.version 的version是属性名字,随便起名,等号后的version是上面的变量。
模块成员导入
a接收了exports对象
./b.js的后缀.js是可以省略掉的
另一种导出方式
exports是module.exports的别名(地址引用关系),导出对象最终以module.exports为准
二、模块化
系统模块
Node运行环境提供的API。因为这些API都是以模块化的方式进行开发的,所以我们又称为Node运行环境的API为系统模块。
系统模块fs文件操作
const fs = require('fs');
读取文件内容
fs.readFile('文件路径/文件名称' [,'文件编码'], callback);
示例
写入文件内容
fs.writeFile('文件路径/文件名称', ’数据', callback);
系统模块path路径操作
路径拼接语法
path.join('路径', '路径', ...)
第三方模块
又称为包。
两种存在形式:
- 以js文件的形式存在,提供现实项目具体功能的API接口。
- 以命令行工具形式存在,辅助项目开发
获取第三方模块
npmjs.com
npm(node package manager):node第三方模块管理工具
下载安装,删除
npm install 模块名称
npm uninstall package 模块名称
全局安装与本地安装
- 命令行工具:全局安装
- 库文件:本地安装
nodemon
一个命令行工具,辅助开发。
使用步骤:
1.使用npm install nodemon -g 下载它 -g全局安装
2.在命令行中使用nodemon命令替代node命令执行文件
nrm
npm下载地址切换工具
为了提高npm的下载地址,切换为国内的地址
1.使用npm install nrm -g 下载它 -g全局安装
2.查询可用下载地址列表nrm ls
3.切换npm下载地址nrm use 下载地址名称
Gulp
基于node平台开发的前端构建工具,将机械化操作编写成任务,想要执行机械化操作时执行一个命令行命令,任务就自动执行了
用机器代替手工,提高开发效率。
能做什么:
使用:
1.使用npm install gulp
2.在项目根目录下建立gulpfile.js文件
3.重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件
4.在gulpfile.js文件中编写任务
5.在命令行工具中执行gulp任务
Gulp中提供的方法:
gulp.src():获取任务要处理的文件
gulp.dest():输出文件
gulp.task():建立gulp任务
gulp.watch():监控文件变化
Gulp插件
package.json文件
项目的描述文件,记录了当前项目信息,例如项目名称、版本、作者、github地址、当前项目依赖了哪些第三方模块等,使用 npm init -y 命令生成。
使用npm install会自动下载该文件中记录的依赖
项目依赖
在项目的开发阶段和线上运营阶段,都需要依赖的第三方包,称为项目依赖。
使用npm install 包名 命令下载的文件会默认被添加到package.json文件的dependencies字段中
开发依赖
在项目的开发阶段需要依赖,线上运营阶段不需要依赖的第三方包,称为开发依赖。
使用npm install 包名 --save-dev命令将包添加到package.json文件的devDependencies字段中
package-lock.json
锁定包的版本,确保下次下载时不会因为包版本不同而产生问题
加快下载速度,因为该文件中已经记录项目所依赖第三方包的树状结构和包的下载地址,重新安装时只需下载即可,不需要做额外的工作
三、前后端数据交互
创建Web服务器
HTTP协议
请求报文
响应报文
状态码
内容类型
请求参数
url模块
// 第一个参数要解析的url地址,第二个参数将url中的参数解析成对象形式 let {query, pathname} = url.parse(req.url, true);
Post请求参数
路由
静态资源
服务器端不需要处理,直接响应给客户端的资源。
相同的请求地址不同的响应资源,这种资源就是动态资源。
第三方模块mime
const querystring = require('querystring'); const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const mime = require('mime'); // 创建web服务器 const app = http.createServer(); // 当客户端发送请求的时候 app.on('request', (req, res)=>{ // 获取用户请求路径 let pathname = url.parse(req.url).pathname; // 将用户的请求路径转换为实际的服务器硬盘路径 let realpath = path.join(__dirname, 'public'+pathname); let type = mime.getType(realpath); fs.readFile(realpath, (error, result)=>{ if(error != null){ res.writeHead(404, { 'content-type': 'text/html;charset=utf8' }) res.end('文件读取失败!') return; } res.writeHead(200, { 'content-type': type }) res.end(result); }) }); // 监听3000端口 app.listen(3000); console.log('服务器已启动,监听3000端口,请访问localhost:3000')
异步编程
异步API
console.log('before'); setTimeout(function(){ console.log('last'); }, 2000) console.log('after');
结果:
定时器在最后执行,没有按顺序从上到下执行,是异步的。
可以从同步API中取到返回结果,不能取到异步API的返回结果。
因为,异步API步阻塞,所以定时器步阻塞,下面没有写返回值,相当于return undefined,因此msg接收到的是undefined。
想拿到异步API的结果,不能使用return,使用回调函数
回调函数
自己定义函数让别人去调用
function getData(callback){ setTimeout(function(){ callback({ msg: 'hello node.js', }) }, 2000) } getData(function(data){ console.log(data); });
同步API从上到下依次执行
异步API不会等待执行完成后再向下执行代码
执行顺序分析
从上到下执行,遇到同步代码放到同步代码区中执行,异步代码放到异步代码区暂不执行,把对应的回调函数放到回调函数队列中, 当所有同步代码执行完后去异步代码区找异步代码,异步代码执行完后,会去回调函数队列找回调函数,然后把回调函数放到同步代码执行区中执行
Promise
目的:解决Node.js异步编程中回调地狱的问题。
创建Promise构造函数的实例对象,创建过程需要传递匿名函数,匿名函数需要两个参数
resolve 是一个函数,当异步API有返回结果的时候,可调用resolve,将异步API结果传递出去
reject 也是函数,异步API执行失败,调用reject,将失败信息传递到外面
promise调用then方法,里面传递函数,该函数实际就是resolve执行的函数
catch则是失败调用的方法,实际是reject调用的函数
使用Promise解决回调地狱问题
几个异步API用几个Promise
为了按顺序执行,可以进行嵌套,但出现了回调地狱问题
const fs = require('fs'); fs.readFile('./1.txt', 'utf8', (err, result1) => { console.log(result1); fs.readFile('./2.txt', 'utf8', (err, result2) => { console.log(result2) fs.readFile('./3.txt', 'utf8', (err, result3) => { console.log(result3) }) }) });
使用Promise
const fs = require('fs'); // fs.readFile('./1.txt', 'utf8', (err, result1) => { // console.log(result1); // fs.readFile('./2.txt', 'utf8', (err, result2) => { // console.log(result2) // fs.readFile('./3.txt', 'utf8', (err, result3) => { // console.log(result3) // }) // }) // }); // function p1(){ return new Promise((resolve, reject) => { fs.readFile('./1.txt', 'utf8', (err, result) => { resolve(result) }); }); } function p2(){ return new Promise((resolve, reject) => { fs.readFile('./2.txt', 'utf8', (err, result) => { resolve(result) }); }); } function p3(){ return new Promise((resolve, reject) => { fs.readFile('./3.txt', 'utf8', (err, result) => { resolve(result) }); }); } p1().then((r1) => { console.log(r1); return p2(); }) .then((r2) => { console.log(r2); return p3(); }) .then((r3) => { console.log(r3); });
解决了回调地狱,但毕竟繁琐
异步函数
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
使用 async 关键字
const fn = async() =>{}; async function fn(){}
async关键字
- 普通函数定义前加async关键字,普通函数变成异步函数
- 异步函数默认返回Promise对象
- 在异步函数内部使用return关键字进行结果返回,结果会被包裹在promise对象中 return关键字代替了resolve方法
- 调用异步函数再链式调then方法获取异步函数执行结果
- 调用异步函数再链式调用catch方法获取异步函数执行的错误信息
// 异步函数默认返回值是Promise对象 // 使用throw关键字进行错误抛出 async function fn(){ throw '发送了一些错误'; return 123; } fn().then(function(data){ console.log(data); }).catch(function(err){ console.log(err); })
await关键字
- 只能出现在异步函数中
- await promise await后面只能写promise对象,写其他类型的API是不可以的
- await关键字可是暂停异步函数向下执行,直到promise返回结果
async function p1(){ return 'p1'; } async function p2(){ return 'p2'; } async function p3(){ return 'p3'; } // await关键字 // 只能出现在异步函数中 // await promise 它可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数 async function run(){ await p1(); await p2(); await p3(); }
const fs = require('fs'); // promisify 改造现有异步函数API,让其返回promise对象,从而支持异步函数语法 const promisify = require('util').promisify;// 调用promisify方法改造现有异步API,让其返回promise对象 const readFile = promisify(fs.readFile); async function run(){ let r1= await readFile('./1.txt', 'utf8'); let r2= await readFile('./2.txt', 'utf8'); let r3= await readFile('./3.txt', 'utf8'); console.log(r1); console.log(r2); console.log(r3); } run()
来源:https://www.cnblogs.com/aidata/p/12275268.html