Node 基本知识点

1.1 确定node环境是否安装成功
	1) 打开cmd命令行,输入`node  --version` 或者 `node  -v`
1.2 Hello World编写
	1) 创建编写 JavaScript 脚本文件
 	2) 打开cmd命令行,通过 `cd`  定位到脚本文件所在的目录
​	3) 在cmd中输入 `node  文件名` 执行对应的文件
注意:文件名不要使用 `node.js` 来命名js文件,也就是说除了 `node` 这个名字你随便起,最好也不要使用中文。
1.3 解析执行JavaScript
	浏览器中的 JavaScript 是没有文件操作的能力的。node 中的 JavaScript 具有文件操作的能力。
	fs 是 file-system 的简写,就是文件系统的意思。在node中如果想要进行文件操作,就必须引入 fs 这个核心模块,在 fs 这个核心模块中,就提供了所有的文件操作相关的 API。
	例如: fs.readFile()就是用来读取文件的; fs.writeFile()就是用来写入文件的。

// 1.使用require方法加载 fs 核心模块
	const fs = require('fs')
// 1.3.1文件读取 fs.readFile(参数1,参数2)
// 第一个参数是要读取的文件路径 `url`
// 第二个参数是一个回调函数
// 成功 (data 是 数据, error 是 null) 失败(data  是 null, error 是  错误对象)
// 读文件
	var fs = require('fs');
	fs.readFile('文件地址',function(error,data){
    	//console.log(data) ---- 此时打印的是16进制数
    	console.log(data.toString())  
	})
	// 注意:文件中 data 存储的其实都是二进制数据 0 1,但是看到的为16进制,原因是二进制转化为16进制了,则我们可以通过toString() 方法把 data(16进制数)转化为我们能认识的字符。
// 写文件
// readFile 的第二个参数是可选额,传入 utf8 就是告诉它把读取的文件按照 utf8 编码。
fs.readFile(文件路径, 'utf8', function(err,data){})
//若省略 utf8, 则获取的数据需要通过 data.toSting() 或者 JSON.parse(data)转为对象。
// 1.4 node 构建 Web 服务器
// 在 node 中,专门提供了一个核心模块: http。http 这个模块的职责就是帮你创建编写服务器的。
// 1.加载 http 核心模块
	var http = require('http');
// 2.使用 http.createServer() 方法创建一个 Web 服务器,返回一个 Server 实例
	var server = http.createServer()
// 3.服务器要干嘛?
//提供服务:对数据服务;发送请求;接受请求;处理请求;给个反馈(发送响应);注册 require 请求事件。
//当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调函数处理。
	server.on('request',function(request,response){
	    //request 请求事件处理函数,需要接收两个参数:
	    //	request 请求对象
	    //	        请求对象可以用来获取客户端的一些请求信息,例如请求路径 request.url。
	    //  response 响应对象
	    //           响应对象可以用来给客户端发送响应消息
	    // response 对象有一个方法:write可以用来给客户端发送响应数据,write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待。
    	console.log('收到客户端的请求了');
    	response.end();
	})
// 4.绑定端口号,启动服务器
	server.listen(3000,function(){
	    console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来访问')
	})
// 简单版
var http = require('http');
http.createServer(function(request,response){
}).listen(端口号,function(){
	console.log('running server...')
})
`IP`  地址用来定位 `计算机``端口号` 用来定位具体的 `应用程序`(所有需要联网通信的软件都必须具有端口号)
// 1.5 art-template 模板
// art-template 不仅可以在浏览器中使用,也可以在 node 中使用
// 安装:
	cnpm  install art-template --save 
// 该命令在哪执行就会把包下载到哪里,默认会下载到 node_modules 目录中,node_modules 文件不要改,也不支持修改。
// 使用方法:
	1)安装 `cnpm install art-template --save`2) 在需要使用的文件模板中加载  art-template
	​3)查文档,使用模板引擎的 API
// 代码风格:以`(` , `[` , ` , 开头,最好在最前面补一个分号 (;) ,避免出现一些问题。
	;()(function(){
    	
	})

在node中使用art-template 模板引擎:

​ 1,安装 cnpm install art-template --save

​ 2,在需要使用的文件模块中加载 art-tempalte

​ 只需要使用 require 方法加载就可以了: var template = require("art-template") 参数中的art-template 就是你下载的包的名字,也就是说你 install 的名字是什么,则你 require 中的就是什么。

​ 3,查文档,使用模板引擎的 API。

​ 4,常用模板语法。

//循坏模板语法
{each 循环变量名}
	{$value} 
{/each}

//条件模板语法                      
{if} 

{else}

{/if}
1.5.1 运用 art-template 模板案例
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>在浏览器中使用art-tempalte</title>
</head>
<body>
	//在浏览器中,需要引用 lib/template-web.js文件
	//01,安装template, 引入template.
	<script src="./node_modules/art-template/lib/template-web.js"></script>
	
	//02,创建模板容器
	<script type="text/template" id="tpl">
		hello {{name}}
	</script>
	
	//03,模板数据
	<script>
		//这里不是浏览器
		//template("script 标签 id",{数据对象})
		var ret = template('tpl',{
			name:"Jack"
		})
		console.log(ret)
	</script>
</body>
</html>
1.5.2 art-template模板案例2
app.js文件
//01,引入所需的 http,fs,art-template模块
var http = require("http");
var fs = require("fs");
var template = require("art-template");

//02,创建服务器
http.creatServer(function(req,res){
    if(err){
        return res.end("文件读取失败。")
    }
    //03,读取demo.html文件
    fs.readFile('./demo.html',function(err,data){
        //04,art-template模板语法,模板数据。
        //fs读取的是二进制数据,而模板引擎的render方法需要接收的是字符串,则需要通过toString()方法转化为字符串或者通过JSON.stringify()转化成字符串。
        var html = template.render(data.toString(),{
            name:"王亚波",
            age:25,
            address:'河南省驻马店市确山县',
            hobbies:['垂钓','爬山']
        });
        res.end(html)
    })
})

//设置端口号
http.listen(3000,function(){
    console.log('服务器启动成功,可通过http://127.0.0.1:3000来访问')
})
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>在浏览器中使用art-tempalte</title>
</head>
<body>
    <h1>我的名字:{{name}}</h1>
    <h2>我的年龄:{{age}}</h2>
    <h3>我来自:{{address}}</h2>
    <h5>我的爱好:{{each hobbice}} {{$value}} {{/each}}</h2> 
    //{{each 循环对象}} {{$value}} {{/each}} 
</body>
</html>
1.5.3 art-template模板案例3
app.js
//引用 http, fs, template模块
var http = require("http");
var fs = require("fs");
var template = require("art-template");

//创建服务器
var server = http.createServer(function(req,res){
    //获取请求路径
    var url = req.url;
    if(url === '/'){
        fs.readFile('./views/demo.html',function(err,data){
            if(err){
                return res.end('404 not found')
            }
            var tmp2 = template.render(data.toString(),{
                name:"王亚波",
                age:25,
                address:"河南省驻马店市确山县",
                hobbies:['游泳','爬山','垂钓']
            });
            res.end(tmp2)
        })

    }else if(url.indexOf('/public/') === 0){
        fs.readFile('./'+url,function(err,data){
            if(err){
                return res.end('404')
            }
            res.end(data)
        })
    }else{
        fs.readFile('./views/404.html',function(err,data){
            res.end(data)
        })
    }
})
server.listen(3000,function(){
    console.log("服务器启动成功,可通过http://127.0.0.1:3000来访问。")
});
demo.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>首页</title>
    <link rel="stylesheet" href="../public/css/main.css">
</head>
<body>
    <h1>我的名字:{{name}}</h1>
    <h2>我的年龄:{{age}}</h2>
    <h3>家庭住址:{{address}}</h3>
    <h4>{{each hobbies}} {{$value}} {{/each}}</h4>
</body>
</html>
1.5.4 获取一个文件中的文件名和目录方法
fs.readdir('文件路径', function(err,files){
    
})

实例:

//通过fs.readdir(文件路径, function(err,files){})
var Dir = "D:/html"
fs.readdir(Dir,function(err,files){
	if(err){
		return res.end("没有要找的文件.")
	}
	console.log(files)
})
1.5.5 求数组的最大值与最小值
Math.max.apply(this,数组名) //获取数组中最大值
Math.min.apply(this,数组名) //获取数组中最小值
Math.max.call(this,数值1,数值2,数值3.....)//call()和apply()传的参数不一样。
1.6 文件操作路径和模块路径
1.6.1 文件操作路径
//   在文件操作的相对路径中
//   ./data/main.txt   相对于当前目录
//   data/main.txt     相对于当前目录
//   /data/mian.txt    绝对路径,当前文件模块所处磁盘根目录
//   c:/xxx/xxx...     绝对路径

fs.readFile('./data/main.txt',function(err,data){
    if(err){
        throw err
    }
    console.log(data.toString())
})
1.6.2 模块操作路径
//这里如果忽略了 . 则就是磁盘根目录
require('/data/main.js') 

//相对路径
require('./data/main,js')
//模块加载的路径中的相对路径不能省略 ./
1.6 服务端渲染与客户端渲染

​ 服务端渲染与客户端渲染的区别

​ 1)客户端渲染不利于 SEO 搜索引擎优化。

​ 2)服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的

​ 3)所以你会发现真正的网站既不是纯客户端渲染出来的,也不是纯服务端渲染出来的,而是两者结合来做的

例如:京东的商品列表就是采用的是服务端渲染,目的为了 SEO 搜索引擎优化,而它的商品评价列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染。

对于服务端渲染来讲,只请求了一次,服务端渲染,响应的就是最终的结果,客户端不需要再做任何处理。

对于客户端渲染来讲,至少需要请求 2 次:第一次请求拿到的是页面;第二次请求拿到的是动态数据。

​ 浏览器收到 html 响应内容之后,就要开始从上到下依次解析,当在解析的过程中,如果发现:linkscriptimgiframevideoaudio 等带有 src 或者 herflink) 属性标签的时候,浏览器会自动对这些资源发起新的请求。

​ 在服务端中,文件中的路径就不要写相对路径了,因为这个时候所有的资源都是通过 url 标识来获取的,我的服务器开放了 /public 目录,所以这里的请求路径都写成: /public/xxx/ 在这里就是 url 根路径的意思,浏览器在真正发请求的时候会最懂把 http://127.0.0.1:3000 拼上,不要在想文件路径了,把所有的路径都想象成 url 地址。

//服务器开放了 public 文件 所有路径不是 ./public,而是 /public
<link rel='stylesheet' href='/public/lib/bootstrap/dist/css/bootstrap.css'>
//开放 public文件
//引入 服务器 http 模块 和文件操作 fs 模块 
var http = require('http');
var fs = require('fs');

//创建服务器
http.creatServer(function(req,res){
	var url = req.url;
	if(url === '/'){
		fs.readFile('./view/index.html',function(err,data){
			if(err){
				return res.end('404 Not Found.')
			}
			res.end(data)
		})
	}else if(url.indexOf('/public/') === 0){
		//路径: /public/css/main.css
		//路径: /public/js/main.js
		//路径: /public/lib/jquery.js
		//统一处理:如果请求路径是以 /public/ 开头的。则说明你要获取 public 中的资源,所以我们就直接可以把请求路径当作文件路径来直接进行读取。 
		fs.readFile('.'+url,function(err,data){
			if(err){
				return res.end('404 Not Found.')
			}
			res.end(data)
		})
	}else{
		//其他的都处理成404找不到
		fs.readFile('./views/404.html',function(err,data){
			if(err){
				return res.end('404 Not Found')
			}
			res.end(data)
		})
	}
})

//设置服务器端口。
http.listen(3000,function(){
	console.log('服务器启动成功,可以通过http://127.0.0.1:3000来访问')
})
1.6.1 客户端渲染过程:

​ (1)收到服务端响应的字符串。

​ (2)从上到下依次解析。在解析的过程中。如果发现ajax请求,则再次发起新的请求。

​ (3)发送请求

​ (4)获取ajax响应结果

​ (5)模板引擎渲染

​ 至少需要两次请求:(1)第一次请求获取的是页面;(2)第二次请求获取的是动态数据。

1.6.2 服务端渲染过程:

​ (1)读取index.html

​ (2)模板引起渲染,在发送给客户端之前,我在服务端就已经把index.html渲染处理好了。Var 渲染结果 = template.render(模板字符串,{解析替换对象})

response.end(渲染结果)。

​ 对于服务端渲染来讲,只需要请求一次。服务端渲染,响应的就是最终的结果,客户端不需要再做任何处理。

客户端渲染不利于SEO搜索引擎优化

服务端渲染是可以被爬虫抓取的。

1.6.3 服务器渲染与客户端渲染的优缺点
服务器渲染的优点:
	(1)前端耗时少,因为后端拼接完了 html,浏览器只需要直接渲染出来。
	(2)有利于SEO,因为在后端是完整的 html页面,所以爬虫更容易爬取获取信息,更有利于SEO.
	(3)无需占用客户端资源,即解析模板的工作完全交由后端来做,客户端只要解析标准的 html页面即可,这样对于客户端的资源占用更少,尤其是移动端,也可以更省电。
	(4)后端生成静态化文件,即生成缓存片段,这样就可以减少数据库查询浪费的时间了,且对于数据变化不大的页面非常高效。
	缺点:
	(1)不利于前后端分离,开发效率低。
	(2)占用服务器资源	
客户端渲染的优点:
	(1)前后端分离。前端专注于前端UI,后端专注于API开发,且前端有更多的选择性,而不需要遵循后端特定的模板。(2)体验更好
	缺点:(1)前端响应较慢;(2)不利于SEO

​ 在服务端中,文件中的路径就不要去写相对路径了,因为这个时候所有的资源都是通过 url 标识来获取的,我的服务器开放了 /public/ 目录,所以这里的请求路径都写成: /public/xxx/ 在这里就是 url 根路径的意思,浏览器在真正发请求的时候会把 http://127.0.0.1:3000 拼上的。

//开放public文件目录
<link rel="stylesheet" href="/public/lib/bootstrap/dist/css/bootstrap.css" />
1.6.4 表单提交以及get参数获取方法

表单中,需要提交的表单控件元素必须要具有 name 属性。

<form action="路径" method="get">
	<div id="name">
		<label for="input_name">姓名</label>
		<input type="text" id="input_name" name="name" required minlength="2" maxlength="10" placeholder="请输入你的姓名"/>
	</div>
	<div id="age">
		<label for="input_age">年龄</label>
		<input type="text" id="input_age" name="age" required minlength="2" maxlength="10" placeholder="请输入你的年龄"/>
	</div>
	<button type="submit">提交</button>
</form>

​ 对于 /views?name='wyb'&age='25' 这种表单提交的请求路径,由于其中具有用户动态填写的内容,所以你不可能通过去判断完整的 url 路径来处理这个请求。

​ 结论:对于我们来讲,其实只需要判定,如果你的请求路径是 /views 的时候,那我们就认为你提交表单的请求过来了。

对于 GET 请求获取参数的方法,使用 url.parse(url,true) 第二个参数为true表示直接将查询字符串转为一个对象。(通过 query 属性来访问)

//使用url.parse方法将路径解析为一个方便操作的对象。
//url.parse(url,true) 第二个参数为true表示直接将查询字符串转为一个对象。(通过query属性来访问)
var url = require('url');

var urlPath = '127.0.0.1:3000/views?name='wyb'&age='26'
var urlObj = url.parse(urlPath,true)
var urlP = urlObj.query

console.log(urlP) //输出结果 {name:'wyb',age:'26'}

单独获取不包含查询字符串的路径部分(该部分不包含 后后面的内容)

 var pathname = url.parse(urlPath,true).pathname.

如何通过服务器让客户端重定向

  1. 状态码设置为 302 临时重定向。 res.statusCode = 302

  2. 在响应头中,通过 Location 告诉客户端往哪重定向 。 res.setHeader('Location','/') 或者 res.setHeader('Location','http://127.0.0.1:3000')

    如果客户端发现收到服务器的响应的状态码是 302 就会自动去响应头中找 Location ,然后对该地址发起新的请求,所以用户就会看到客户端自动跳动。

  3. 路由重定向:res.redirect( 跳转地址 ) 例如:跳转到首页 res.redirect('/')

1.7 Nodemon 修改完代码自动启动服务器

可以使用一个第三方命令行工具:nodemon 解决频繁修改代码重启服务器问题。

nodemon 是一个基于Node.js 开发的一个第三方命令行工具,需要独立安装。

npm install --global nodemon  //全局安装

安装完毕之后,使用:

//不使用 node 文件名
node app.js

//使用 nodemon 文件名
nodemon app.js

只要是通过 nodemon app.js 启动的服务器,则它会监视你的文件变化,当文件发生变化的时候,自动帮你重启服务器。

2,Node模块系统Express 第三方 Web 开发框架

​ 使用框架的目的就是为了让我们更加专注于业务,而不是底层细节。

​ 使用 Node 编写应用程序主要就是在使用:

​ (1) EcmaScript 语言。和浏览器不一样,在 Node 中没有 BOMDOM

​ (2)核心模块。

​ 1) 文件操作模块 fs; 如: 文件读操作: fs.readFile()文件写操作:fs.writeFile()

​ 2) http 服务模块 http;如:服务器创建: http.creatServer

​ 3) url 路径操作模块 url;如:url参数解析: url.parse

​ 4)path 文件路径处理模块; 如:文件路径__dirname__filename path.join()

​ 5) os 操作系统模块。

​ (3)第三方模块。art-template 必须通过 npm 安装后,才可以使用。

​ (4)自己写的模块。

2.1,CommmonJS 模块规范

​ 在 node中的 JavaScript 还有一个重要的概念:模块系统

​ (1)模块作用域;(2)使用 require 方法用来加载模块;(3)使用exports接口对象用来导出模块中的成员。

2.1.1,exports 与 module.exports

exports :是一个对象,我们可以通过 exports 向外导出多个内部成员。如下例 main.js引入 info.js文件。

main.js 文件:

var obj = require('./info')

//导出的obj对象形式如下
//obj = {
//	str:"hello world"
//	add:function(x,y){
//        return x+y
//    }
//}

console.log(obj.add(2,3)) //打印结果 5
console.log(obj.str) // 打印结果 hello world

info.js 文件:

var str = "hello world";

function add(x,y){
    return x+y
}

//使用 exports.xxx = xxx可以同时导出多个内部成员。
exports.str = str;
exports.add = add;

module.exports:只能向外导出一个成员,而非挂载的方式。

module.exports 导出单个成员:

var str = "Hello world";

function add (x,y){
    return x+y
}

//module.export只能导出一个成员;后者会覆盖前者。
module.exports = add;
module.exports = str; //最终导出的成员

module.exports 导出多个成员:

module.exports = {
    str:"hello world",
    add:function(x,y){
        return x+y
    }
}

真正去使用的时候

导出多个成员:exports.xxx = xxx;
导出多个成员也可以:module.exporrts = {
    
}
导出单个成员:module.exports = 导出变量。 
2.1.2,exports 与 module.exports 原理解析

谁来 require 我,谁就得到 module.exports 一定要记住,最后 return 的是 module.exports 而不是 exports ,所以你给 exports 重新赋值是不管用的。 return module.exports

(1)开始 exportsmodule.exports 的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aeQNvZWf-1688139180891)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20200105162413136.png)]

(2)赋值后的关系

注意: 最终返回的是 return module.exports

2.2,加载 require

语法:

var 自定义变量名 = require('模块名称'

两个作用:(1)执行被加载模块中的代码;(2)得到被加载模块中的 exports 导出的接口对象。

2.2.1,伪数组转化真数组

​ (1) Array.from(arr) 或者 [].slice.call(arr)

//arrF 是伪数组,伪数组必须包含 length 属性。
var arrF = {
    0:'hello',
    1:'world',
    2:'wyb',
    length:3
}
//方法一,伪数组转化成数组
Array.from(arrF) //输出结果:['hello','world','wyb']
//方法二
[].slice.call(arrF) //输出结果:['hello','world','wyb']
2.2.2,状态码

301: 永久重定向,浏览器会记住。

**302:**临时重定向。

2.2.3,require 方法加载规则
  • 核心模块。(模块名)如:var fs = require("fs")

  • 第三方模块。(模块名)如: var template = require("art-template")

  • 用户自己写的。(路径)如:var main = require("./main")

    模块加载顺序:优先从缓存中加载核心模块路径形式的模块

实例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ligGDTUP-1688139180893)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20200105204820728.png)]

​ 由于在a.js文件中,已经加载过了b.js文件,所以这里不会重复加载,但是可以拿到其中的接口对象,不会重复执行里面的代码。这样做的目的是为了避免重复加载,提高模块加载效率。

如果是非路径形式的模块标识。

​ 路径形式的模块:./ 当前目录,不可省略。 ../ 上一级目录,不可省略。首位的 / 在这里表示的是当前文件模块所属磁盘根目录路径。

核心模块的本质也是文件,核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了。

var fs = require("fs");
var http = require("http");
var path = require("path");
var url = require("uel")

第三方模块,凡是第三方模块都必须通过 npm 来下载,使用的时候就可以通过 require("包名") 的方式进行加载才可以使用。不可能有任何一个第三方包和核心模块的名字是一样的。

​ 如果 package.json 文件不存在或者 main 指定的入口模块也没有,则 node会自动找到该目录下的 index.js 也就是说 index.js 会作为一个默认备选项。如果以上所有任何一条都不成立,这会进入上一级目录中的 node_modules 目录查找,如果上一级还没有,则继续往上上一级查找。如果直到当前磁盘根目录还找不到,最后报错:can not find modules xxxvar tempalte = reqiure("art-template") 注意:我们一个项目有且只有一个 node_modules ,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包;不会出现多个 node_modules .

​ 模块查找机制:(1)优先从缓存加载;(2)核心模块;(2)路径形式的文件模块;(3)第三方模块。

  1. node_modules/art-template/

  2. node_modules/art-template/package.json

  3. node_modules/art-template/package.json 中的 main

  4. index.js 备选项。

  5. 进入上一级目录找 node_modules

    按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:can not find modules xxx

2.2.4, npm 及 常见命令
**npm:** node package manager

npm 的第二层含义就是一个命令行工具,只要你安装了 node 就已经安装了 npm

npm 也有版本这个概念。可以通过在命令行中输入:

 npm --version 或者 npm -v

升级 npm (自己升级自己)

npm install --global npm

常见命令

npm init 初始化项目 或者 npm init -y (可以跳过向导,快速生成)
npm install (一次把dependencies选项中的依赖项全部安装) 或者 npm i
npm install 依赖名 (只下载) 或者 npm i 依赖名
npm install 依赖名 --save (下载并保存依赖项) 或者 npm i -s 依赖名
npm uninstall 依赖名 (只删除,依赖项仍保存) 或者 npm un 依赖名
npm uninstall 依赖名 --save (删除同时删除依赖性) 或者 npm un -s 依赖名
npm help (查看帮助)
npm 命令 --help (查看指定命令的使用帮助) 例如 npm uninstall --help。 
2.2.5,package.json 包描述文件

​ 我们建议每个项目都要有一个 package.json 文件(包描述文件,就像产品的说明书一样)。

​ 这个文件可以通过 npm init 的方式初始化出来。对我们来说,最有用的是哪个 dependencies 选项,可以用来帮助我们保存第三方包的的依赖信息。如果你的 node_modules 删除了也不用担心,我们只需在命令行中输入: npm install 就会自动把 package.json 中的 dependencies 中所有的依赖项都下载回来。

​ 建议每个项目的根目录下都有一个 package.json 文件。

​ 建议执行 npm install 包名 的时候都加上 --save 这个选项,目的是用来保存依赖项信息。

npm install 依赖名  --save
3,Web应用程序开发框架 Express的使用
3.1 安装
cnpm install express --save

2. 通过express 创建服务器

01. 创建一个简易的服务器

//01.安装 express依赖项
//02.引入 express 包文件
var express = require("express");

//03.创建你服务器应用程序,也就是原来的 http.createServer()
var app = express();

//04.当服务器收到 get 请求 / 的时候,执行回调处理函数。
app.get('/',function(request,response){
    response.send('hello express.')
})

//05.监听端口,相当于 server.listen()
app.listen(3000,function(){
    console.log("服务器已经启动,可以通过http://127.0.0.1:3000来访问。")
})

02.创建复杂的服务器

//1. 安装 express 依懒项 npm install express --save
//2. 引入 express 包文件
var express = reqiure("express");

//3. 创建服务应用程序
var app = express()

//公开指定目录
//只要这样做了,你就可以直接通过 /public/xxx 的方式访问 public 目录中的所有资源。
//如:127.0.0.1:3000/public/index.html
app.use('/public/',express.static('./public/'))
app.use('/static/',express.static('./static/'))
app.use('/node_modules/',express.static('./node_modules/'))

//4. 服务器请求
app.get('/',function(req,res){
    //在 express 中可以直接 req.query 来获取查询字符串参数
    var urlquery = req.query;
    console.log(urlquery)
    
    res.send("hello express")
})

//设置端口号
app.listen(3000,function(){
    console.log("app is running at port 3000")
})

express 中, app.use() 可用于公开指定目录;req.query 用来获取 get 方式字符串参数。

express 中,使用模板引擎有更好的方式:res.render('文件名', {模板对象})

3.2 基本路由

路由器

(1)get

//当你以 GET 方式请求 / 的时候,执行对应的处理函数
app.get('/', function(req,res){
    res.send('hello world.')
})

(2)post

//当你以 POST 方式请求 / 的时候,指定对应的处理函数
app.post('/', function(req,res){
    rse.send('hello world.')
})

公开指定文件

//01.只要这样做了,你就可以直接通过 /public/xxx 的方式访问 public 目录中的所有资源。(推荐使用)
//如:127.0.0.1:3000/public/index.html
app.use('/public/',express.static('./public/')) 

//02.当省略第一个参数的时候,则可以通过省略 /public 的方式来访问。
//如:127.0.0.1:3000/index.html
app.use(express.static('./public/'))
3.2 开放静态文件服务
//  /public资源
app.use(express.static('public'))

//  /files资源
app.use(express.static('files'))

//  /public/xxx
app.use('/public', express.static('./public/'))

//  /static/xxx
app.use('public', express.static('./public/c'))

app.use('/public/', express.static(path.join(__dirname, 'public')))
3.3 在 express 中配置使用 art-template 模板引擎

1. 安装

npm install --save art-template
npm install --save express-art-template

2. 配置

​ 配置使用 art-template 模板引擎,第一个参数表示,当渲染以 .art 结尾的文件的时候,使用 art-template 模板引擎。 express-art-template 是专门用来在 express 中把 art-tempalte 整合到 express中,虽然外面这里不需要加载 art-template 但是也必须安装,原因就在于 express-art-tempalte 依赖于 art-tempalte

//当渲染以 .html 结尾的文件,使用 art-template 模板引擎。
app.engine('html', require('express-art-template')) 

3. 使用

expressresponse 相应对象提供了一个方法: renderrender 方法默认是不可以使用,但是如果配置了模板引擎就可以使用了,res.render('html模板名', {模板数据}) ,第一个参数不能写路径,默认会去项目中的 views 目录中查找该模板文件。也就是说 express 有一个约定:开发人员把所有的视图文件都放到 views 目录中。

app.get('/',function(req,res){
    // express 默认会去项目中的 views 目录中找 index.html文件,可以通过app.set()设置。
    res.render('index.html',{
        title:'首页'
    })
})
//注意:第一个参数 views 千万不要写错。
//如果想要修改默认的 view 目录,则可以使用:
app.set('views',目录路径)
3.3.1 在 express 其他知识以及获取GET请求的参数
//引入 url 核心模块
var url = require("url")

app.get('/index', function(req,res){
    //获取请求路径 url
    var urlPath = req.url;
    
    //获取 GET 请求方式的路径参数
    var comment =  url.parse(urlPath,true).path;
    comments.unshif(comment);
    
    res.redirect('/') //路由重定向首页
    // 或者 res.statusCode = 302 设置临时重定向状态码。
    //res.setHeader('Location', '/') 设置请求路径。
})
req.parse(url,true).query 只能获取 GET 请求参数
3.3.2 在 express 获取表单 POST 请求体数据

express 中没有内置获取表单 POST 请求体的 API,这里我们需要使用一个第三方包: body-parser ,配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前。

1. 安装

npm install --save body-parser

2.导入

var bodyParser = require('body-parser')

3. 配置

//配置 body-parser 中间件(插件, 专门用来解析表单 POST 请求体)
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ entended:false }))

// parse application/json
app.use(bodyParser.json())

4.使用

var express = require("express");
var bodyParser = require("body-parser");

var app = experss();

// 配置 body-parser
//只要加入这个配置,则在 req 请求对象上会多出来一个属性:body
//也就是说你就可以直接通过 req.body 来获取表单 POST 请求体数据了。
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ entended:false }))
//parse applicaton/json
app.use(bodyParser.json())

//通过 req.body 来获取 POST 请求参数。
app.use(function (req, res) {
  res.setHeader('Content-Type', 'text/plain')
  res.write('you posted:\n')
    //可以通过 req.body 来获取表单 POST 请求体数据
  res.end(JSON.stringify(req.body, null, 2))
})
3.3.3 路由设计

router.js 路由模块职责:处理路由,根据不同的请求方式+请求路径设置具体的请求处理函数。

请求方法请求路径get参数post参数备注
GET/students渲染首页
GET/students/new渲染添加学生页面
POST/studentsname,age,gender,hobbies处理添加学生请求
GET/students/editid渲染编辑页面
POST/students/editid, name, age, gender, hobbies处理编辑请求
GET/students/deleteid处理删除请求

router.js路由提取方法一:

app.js文件

var express = require("express");
var app = express();

//导入路由文件
var router = require("./router")

app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/',express.static('./public/'))

app.engine('html', require('express-art-template'));

//把 app 传入路由文件
router(app)

app.listen(3000, function(req,res){
    console.log("running app server.")
})

router.js文件

module.exports = function(app){
    //get 方式请求学生界面
    app.get('/students',function(req,res){
        
    })
    
    app.get('./students/edit', function(req,res){
        
    })
}

router.js路由提取方法二(常用方法):

app.js文件

var express = require("express")
var router = require("./router")

var app = express();

app.use('/node_modules/', express.static("./node_modules/"));
app.use('/public/', express.static("./public/"))

//把路由容器挂载到 app 服务中
app.use(router)

app.listen(3000,function(){
    console.log("running app server.")
})

router.js文件

//express 提供了一种更好的方式,专门用来包装路由。
var express = require("express")

//01. 创建一个路由容器
var router = express.Router()

//02. 把路由都挂载到 router 路由容器中
router.get('/students', function(req,res){
    
})
router.get('/students/edit', function(req,res){
    
})
router.post('/student/new',function(req,res){
    
})

//导出路由
module.exports = router;
3.4 回调函数

如果需要获取一个函数中,异步操作 的结果,则必须通过 回调函数 来获取

​ **回调函数:**获取异步操作的结果。

function fn (callvack){
    //相当于: var callback = function(data){console.log(data)}
    
    // 因为setTimeout是异步操作,获取里面的值,需要回调函数。
    setTimeout(function(){
        var data = "hello world.";
        callback(data)
    },1000)
}

//如果需要获取一个函数中,异步操作的结果,则必须通过回调函数来获取。
// 调用方式:
fn(function(data){
    console.log(data)
})
3.5 异步函数执行流程

​ 凡是需要得到一个函数内部异步操作的结果,则必须通过:回调函数

​ 异步操作有:setTimeout readFile writeFile ajax

console.log(1);
setTimeout(function(){
    console.log(2)
    console.log("hello")
},0)

console.log(3)

//执行结果:1 3 2 hello 
// 原因:setTimeout 定时器是异步操作,执行完后面的操作,在执行异步里面的代码。
//解决办法:用回调函数

不成立的情况:

var ret
function add(x,y){
    console.log(1)
    //因为setTimeout是异步操作,要想获取异步操作的返回值,则需要回调函数。
    setTimeout(function(){
        console.log(2)
        ret = x+y;
        return ret;
    },1000)
    console.log(3)
}

console.log(add(20,30)) // => 输出结果:undefined
//最终结果:1 3 undefined 2

回调函数:

function add(x,y,callback){  //callback回调函数。
    console.log(1)
    setTimeout(function(){
       var ret = x+y
        callback(ret)
    },1000)

}

add(10,20,function(data){
    console.log(ret)
})
3.5.1 原生的 ajax请求封装 GET 方法。
function get(methods,url,callback){
    var xml = new XMLHttpRequest();
    xml.open(methods,url);
    xml.send();
    xml.onload = function(){
        callback(xml.responseText)
    }
}

//调用方式:
get(get,'./data.json',function(data){
    console.log(data)
})

或者

 //封装原生的ajax请求。
function get(method,url,callback){
    var xml = new XMLHttpRequest();
    xml.open(method,url)
    xml.send()
    xml.onreadystatechange = function(){
        if(xml.readyState === 4){
            if(xml.status >= 200 && xml.status <=207 || xml.status === 304){
                callback(JSON.parse(xml.responseText))
            }
        }
    }
}

//调用方式。
get('GET','http://localhost:3000/users',function(data){
    console.log(data)
})
3.6 package.json 和 package-lock.json

npm 5 以前是不会有 package-lock.json 这个文件的,npm 以后才加入了这个文件。当你安装包文件的时候,npm 都会生成或者更新 package-lock.json 这个文件。

  • npm 5 以后的版本安装包不需要加 --save 参数,它会自动保存依赖信息。

  • 当你安装包文件的时候,会自动创建或者是更新 package-lock.json 这个文件。

  • package-lock.json 这个文件会保存 node_modules 中所有包的信息(版本,下载地址),这样的话重新 npm install 的时候速度就可能提升。

  • 从这个文件看,有一个 lock 称之为锁。这个 lock 是用来锁定版本的;如果项目依赖了 1.1.1 版本;如果你重新 install 其实会下载最新版本,而不是 1.1.1 ;我们的目的就是希望可以锁住 1.1.1 这个版本;所以这个 package.lock.json 这个文件的另一个作用就是锁定版本号防止自动升级新版本

    package-lock.json 文件的作用:(1)下载速度更快了;(2)锁定版本

3.6.1 Ecmascript6 对数组新增的方法

​ 数组的遍历方法,都是对函数作为参数一种运用。

​ 常用的遍历方法:everysomeincludesmapreducefindfindIndex

//find 接受一个方法作为参数,方法内部返回一个条件,
//find会遍历所有的元素,执行你给定的带有条件返回值的函数。
var arr = [1,2,3,4,5]

var ret = arr.find(function(val,index){
    return val > 3
})

console.log(ret) //结果:4  => 数值
//只返回一个符合条件的值

var retIndex = arr.findIndex(function(val,index){
    return val > 3
})

console.log(retIndex) //输出结果:3  =>索引值
//只返回一个符合条件的索引值,
3.7 Javascript 模块化

​ 无论是 CommonJSAMDCMDUMDEcmascript 6 Modules 官方规范 都是为了解决 Javascript 的模块化问题。AMD 第三方库 requireJSCMD 第三方库 seaJS

4 MongoDB数据库

​ MongoDB 数据库:灵活,不用设计数据表,业务的改动不需要关心数据表结构。

4.1 关系型数据库和非关系型数据库

​ 表就是关系,或者说表与表之间存在关系。

关系型数据库:

  • 所有的关系型数据库都需要通过 sql 语句来操作。
  • 所有的关系数据库在操作之前都需要设计表结构。
  • 而且数据表还支持约束。(唯一的,主键,默认值,非空)

非关系型数据库:

  • 非关系型数据库非常的灵活。
  • 有的非关系型数据库就是 key-valuse 对(键 -> 键值),即键值对的关系。
  • 但是 MongoDB 是长的最像关系型数据库的非关系型数据库。
    • 数据库 -> 数据库
    • 数据库 -> 集合(数组)
    • 表记录 -> (文档对象)
  • MongDB 不需要设计表结构,也就是说,你可以任意的往里面存数据,没有结构性这么一说。
4.2 MongoDB 数据库的基本概念
  • 可以有多个数据库。
  • 一个数据库中可以有多个集合(表)。
  • 一个集合中可以有多个文档(表记录)
  • 文档结构很灵活,没有任何限制。
  • MongoDB非常灵活,不需要像 MySQL一样先创建数据库,表,设计表结构。
    • 在这里只需要,当你需要插入数据的时候,只需要指定往哪个集合操作就可以了,一切都由 MongoDB 来帮你自动完成建库这件事。

形如:

{
    qq:{
        users:[
            {name:"张三",age:28},
            {name:"李四",age:18},
            {name:"王二",age:25}
            ....
        ],
        product:[
            
        ]
    },
    taobao:{
        
    },
    baidu:{
        
    }
}
4.3 安装
4.3.1 查看 MongoDB 数据库是否安装成功。
mongod --version 
4.4 启动和关闭数据库

启动数据库

// mongodb 默认使用执行 mongod 命令所处盘符根目录下的 /data/db 作为自己的数据存储目录
// 所以在第一次执行该命令之前先手动新建一个 /data/db 文件
// 启动 Mongodb数据库,只需要在命令行中输入 mongod
mongod

如果想要修改默认的数据存储目录,可以:

mongod --dnpath=数据存储目录路径

关闭数据库

//在启动服务的命令控制台,直接 ctrl+c 即可关闭数据库。或者直接关闭开启服务的控制台。
4.5 连接和退出数据库

连接数据库

//该命令默认连接本地的 MongonDB 数据库
mongo

退出数据库

//在连接状态输入 exit 退出连接
exit
4.6 基本命令
show dbs  //参看显示所有数据库

db  // 查看当前操作的数库

use 数据库名称  //切换到指定的数据库(如果没有会新建)

db.表名称.insertOne()  //插入一条数据,参数是一个对象

show collections  //查看所有的表文件

db.表名称.find()  //查找表中所有的数据
4.7 在 node 中如何操作 MongoDB 数据库。

MongoDB文档

第三方MongooseJs文档

4.7.1 使用官方的 Mongodb包来操作

官方MongoDB使用方法

4.7.2 使用第三方 Mongoose 来操作 MongoDB 数据库

第三方包:mongoose 基于 MongoDB 官方的 MongoDB 包再一次做了封装。Mongoose 所有的 API 都支持 Promise

01,安装 mongoose 包文件

npm install --save mongoose

02,使用安装的 Mongoose 数据库

实例1:

//引入 mongoose 包文件。
var mongoose = require("mongoose");

//连接本地数据库,数据库名为 test
mongoose.connect('mongodb://localhost/test',{useMongoClient:true});

mongoose.Promise = global.Promise;

//创建一个模型,就是在设计数据库,MongoDB 是动态的,非常灵活,只需要在代码中设计你的数据库就可以了。
//Mongoose 这个包就可以让你的设计编写过程变的非常的简单。
var Cat = mongoose.model('Cat',{
    name:string
})

//实例化一个 Cat
var kitty = new Cat({
    name:"wyb"
})

//持久化保存 kitty 实例
kitty.save(function(err,data){
    if(err){
        console.log(err)
    }
    console.log('数据保存成功.');
    console.log(data) // data就是你所插的数据 -- {name:"wyb"}
})
4.8 官方指南
4.8.1 设计 Scheme 发布 Model
var mongoose = require("mongoose");

var Schema = mongoose.Schema;

// 01. 连接数据库
// 指定连接的数据库不需要存在,当你插入第一条数据之后就会自动被创建出来。
mongoose.connect('mongodb://localhost/itcast')

// 02. 设计文档结构(表结构)
// 字段名称就是表结构中的属性名称, 约束的目的是为了保证数据的完整性,不要有脏数据。
var userSchema = new Schema({
    username:{
        type:String,   //  约束条件,默认值,是否必填,数据类型
        require:true
    },
    password:{
        type:String,
        require:true
    },
    email:{
        type:string
    }
})

// 03. 将文档结构发布为模型
// mongoose.model 方法就是用来将一个架构发布为 model
//  第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
//		mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称。
//		例如:这里的 User 最终会变成 users 集合名称
//  第二个参数:架构 Schema

//	返回值:模型构造函数
var User = mongoose.model('User',userSchema)
4.8.2 增加数据
var userList = new User({
    username:'admin',
    password:'123456',
    email:'admin@163.com'
})

userList.save(function(err,data){
    if(err){
        console.log("数据存储失败.")
    }
    console.log("数据存储成功.")
    console.log(data)
})
4.8.3 查询数据

查询所有数据:

User.find(function(err,data){
    if(err){
        console.log("查询失败")
    }else{
        console.log(data)
    }
})

按条件查询所有符合条件的数据:

User.find({
    username:"admin"    //查询的添加
},function(err,data){
    if(err){
        console.log("查询失败.")
    }else{
        console.log(data)
    }
})

按条件查询一条符合条件的数据:

User.findOne({
    username:"admin"
},function(err,data){
    if(err){
        console.log("查询失败.")
    }else{
        console.log(data)
    }
})
4.8.4 删除数据

按照条件删除所有符合添加的数据:

User.remove({
    username:'admin'
}, function(err,data){
    if(err){
        console.log("删除失败.")
    }else{
        console.log(data)
    }
})

根据条件删除一个:

Model.findOneAndRemove(conditions,[options],[callback])

根据 id 删除一个:

Model.findByIdAndRemove(id,[options],[callback])
4.8.5 更新数据库数据

根据条件更新所有:

Model.updata(conditions, doc, [options], [callback])

根据指定条件更新一个:

Model.findOneAndUpdate([conditions], [update],[options],[callback])

根据 id 更新一个:

User.findByIdAndUpdate("id名",{
    password:'123'
},function(err,data){
    if(err){
        console.log("更新失败.")
    }
    console.log("更新失败.")
    console.log(data)
})
4.9 MongoDB基本操作
//文档中的user代表的是表名称。

// 1.查看所有数据库: 
show dbs

// 2.切换到数据库runoob: 
use runoob  //use 数据库名

// 3.创建集合(创建数据库):
// db.表名称.insert()
db.createCollection("user") 或是
db.user.insert({
    "name":"菜鸟教程",
    "class":"初三"
})  //直接创建表及插入数据

// 4.插入文档/数据:  user=表名
db.user.insert({
   "userid":101,
    "username":"秀秀",
    "age":20,
    "class":{
        "classname":"初三",
        "num":6
    }
})

// 5.删除:  
// a.删除数据库
db.dropDatabase() //(切记要先切换到要删除的数据库 然后在直接该语句) 
// b.删除集合/表user代表表名称:
db.user.drop()
// c.删除某一条数据
db.user.remove({'username':'秀秀'})
// d.删除表内所有数据
db.user.remove({})

// 6.查看table的数据:user是表名
// a.查看table的数据:
db.user.find()
db.user.find().pretty() pretty() // 方法以格式化的方式来显示所有文档。
// b.找到第一条数据 :db.user.findOne() 
// c.查找范围:
db.user.find({"age" : {$gt : 20}})  // 大于20岁的数据
db.user.find({"age": {$gte : 20}})  // 大于等于20岁的数据
db.user.find({"age": {$lt : 20}})   // 小于20岁的数据
db.user.find({"age": {$lte : 20}})  // 小于等于20岁的数据
db.user.find({"age": {$lt :30, $gt : 10}})  // 大于10 小于30的数据
// 7.更新文档:
// a.更新
db.user.update({查找的条件},{$set:{更新的内容}})
// b.更新子文档:class.num
db.user.update({'username':'秀秀'},{$set:{'class.num':3}})
5 Node 操作 mysql 数据库
var mysql = require("mysql");

// 1. 创建数据库
var connection = mysql.createConnection({
    host:"localhost",  // 主机名
    user:"me",  //用户名
    password:"secret",
    database:"my_db"
})

// 2. 连接数据库
connection.connnect();

// 3. 执行数据操作
//查找所有的数据
connection.query('SELECT * FROM `users`', function(err,result,fields){
    if(err){
        throw err
    }
    console.log('The solution is:',results)
});
//插入一条数据
// connectiong.query("INSERT INTO users VALUES(NULL,''admin','123456')",
//function(err,result,fields){
//	if(error){
//		throw err
//	}
//	console.log("The solution is:",result);
//})

// 4. 关闭连接
connection.end();
6 Promise 异步操作解决方案

​ 为了解决回调地狱嵌套问题(无法保证代码执行的顺序,不如同时读取多个文件操作),EcmaScript6 新增了一个 API : PromisePromise 其实是一个容器,里面存放了一个异步任务。回调地狱:异步操作嵌套异步操作。

Promise 图解运行机制

抛出异常常见的方式:

var fs = require("fs");

fs.readFile('./a.txt',function(err,data){
	if(err){
		throw err
	}
    console.log(data)
})

//或者

fs.readFile('./a.txt',function(err,data){
    try{
        console.log(data)
    }catch(err){
        console.log(err)
    }
})
6.1 Promise 创建

简单实例:

var fs = require("fs")

// 创建 Promise 容器
// 1. 给别人一个承诺 I promise you.
//     Promise 容器一旦创建,就开始执行里面的代码。
var p1 = new Promise(function(resolve,reject){
    fs.readFile('./a.txt',function(err,data){
        if(err){
            //失败了,承诺容器中的任务失败了,容器里的状态:pending -->  reject
          	reject(err)
        }
        //成功了,承诺容器中的任务成功了,容器里的状态:pending  --> resolve
        resolve(data)
    })
})

// 调用方法
// p1就是那个承诺,
// 当 p1 成功了,然后 then 做指定操作,then 方法接收的 function 就是容器中的 resolve 函数。
p1.then(function(data){
    console.log(data)
}).catch(function(err){
    console.log(err)
})

promise 程序解析过程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4aS6J9e-1688139180895)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20200107195404754.png)]

简单实例2:

var fs = require("fs")

// 读取 a.txt 中的数据
var p1 = new Promise(function(resolve,reject){
    fs.readFile('./a.txt',function(err,data){
        if(err){
            //失败了,承诺容器中的任务失败了,容器里的状态:pending -->  reject
          	reject(err)
        }
        //成功了,承诺容器中的任务成功了,容器里的状态:pending  --> resolve
        resolve(data)
    })
})

// 读取 b.txt 文件中的数据
var p2 = new Promise(function(resolve,reject){
    fs.readFile('./b.txt',function(err,data){
        if(err){
            //失败了,承诺容器中的任务失败了,容器里的状态:pending -->  reject
          	reject(err)
        }
        //成功了,承诺容器中的任务成功了,容器里的状态:pending  --> resolve
        resolve(data)
    })
})

// 读取 c.txt 文件中的数据
var p3 = new Promise(function(resolve,reject){
    fs.readFile('./c.txt',function(err,data){
        if(err){
            //失败了,承诺容器中的任务失败了,容器里的状态:pending -->  reject
          	reject(err)
        }
        //成功了,承诺容器中的任务成功了,容器里的状态:pending  --> resolve
        resolve(data)
    })
})

//实现先读取 a.txt 文件中的数据,再读取 b.txt 中的数据,最后读取 c.txt 中的数据。
// 调用方法
// p1就是那个承诺,
// 当 p1 成功了,然后 then 做指定操作,then 方法接收的 function 就是容器中的 resolve 函数。
p1.then(function(data){
    console.log(data)
// 当 p1 读取成功的时候,当前函数中 return 的结果就可以在后面的 then 中 function 接收到。
// 当你 return 123 后面就接收到 123
// return "hello" 后面就接受到 "hello"
// 没有 return 后面就接收到 undefined
// 上面哪些 return 的数据没有什么用,真正有用的是:我们可以 return 一个 Promise 对象,则也不返
// 回这个 Promise对象。
//当 return 一个 Promise 对象的时候,后续的 then 中的方法第一个参数会作为 p2 的 resolve。如上图 
    return p2
}).then(function(data){
    console.log(data)
    return p3
}).then(function(data){
    console.log(data)
}).catch(function(err){
    console.log(err)
})

实例3:封装 Promise 版本的 readFile

var fs = require("fs")

function readFileP(filePath){
    var promise = new Promise(function(resolve,reject){
        fs.readFile(filePath,function(err,data){
            if(err){
                reject(err)
            }
            resolve(data)
        })
    })
    return promise
}

//实现先读取 a.txt 文件中的数据,再读取 b.txt 中的数据,最后读取 c.txt 中的数据。
//调用方式
readFilep('./a.text').then(function(data){
    	console.log(data)
    	return readFilep('./b.txt')
	}).then(function(data){
    	console.log(data)
   	 	return readFilep('./c.txt')
	}).then(function(data){
    	console.log(data)
	})

6.2 Promise 封装的 get 请求
// Promise封装 GET 请求。
function get(url){
    return new Promise(function(resolve,reject){
        var xml = new XMLHttpRequest();
        xml.open('GET',url);
        xml.send();
        xml.onload = function(){
            resolve(xml.responseText)
        }
        xml.onerror = function(){
            reject(xml.responseText)
        }
    })
}

// 调用方式:
get('http://127.0.0.1:3000').then(function(data){
    console.log(data)
}).catch(function(err){
    console.log(err)
})
6.3 回调函数方式封装的 GET 请求
function get(url,callback){
    var xml = new XMLHttpRequire()
    // 当请求加载成功之后,要调用指定的函数。
    xml.open("GET",url)
    xml.send()
    xml.onload = function(){
        callback(xml.responseText)
    }
}

// 调用方式:这样才能同时获取userData和jobData中的数据。
get('http://127.0.0.1/user/4',function(userData){
    get('http://127.0.0.1/use/2',function(jobData){
        console.log(userData,jobData)
    })
})
7. 开启一个 json 数据接口
7.1 安装插件
cnpm install -g json-server 
7.2 开启接口数据
json-server --watch json文件名

// josn-server --watch db.json
8. http-server 搭建轻量级 web 服务器
8.1. 安装插件
npm install -g http-server
8.2 在要打开的项目文件夹处打开命令窗口,输入如下命令:
hs
9. path 路径操作模块
(1) path.basename // 获取一个路径的文件名(默认包含扩展名)

(2) path.dirname // 获取一个路径中的目录

(3) path.extname // 获取一个路径中的扩展部分

(4) path.parse // 把一个路径转为对象

(5) path.join // 当你需要进行路径拼接的时候,推荐使用这个方法。

(6) path.isAbsolute // 判断一个路径是否是绝对路径。
10. Node 中的其他成员

在每个模块中,除了 requireexports 等模块相关 API 之外,还有两个特殊的成员:

__dirname 动态获取可以用来获取当前文件模块所属目录的绝对路径。
console.log(__dirname) // eg: C:\Users\86135\Desktop\笔记 (注意:不带文件名)

__filename 动态获取可以用来获取当前文件的绝对路径。(注意:带文件名)
console.log(__filename) // eg:C:\Users\86135\Desktop\笔记\读目录__dirname.js

__dirname 和 __filename 是不受执行 node 命令所属路径影响的。

​ 在文件操作中,使用相对路径是不可靠的,因为在 Node 中文件操作的路径被设计为相对于执行 node 命令所处的路径(不是 bug,人家这样设计是有使用场景的)。所以为了解决这个问题,很简单,只需要把相对路径变为绝对路径就可以了。哪这里我们可以使用 __dirname 或者 __filename 来帮助我们解决这个问题了。在拼接路径的过程中,为了避免手动拼接带来的一些低级错误,所以推荐多使用:path.join() 来辅助拼接。

var path = require("path")

console.log(path.join(__dirname,"db.json")) 
11. 在 express 中使用 session cookie

express 这个框架中,默认不支持 sessioncookie ,但是我们可以使用第三方中间件:express-session 来解决

11.1 安装
npm install express-session
11.2 配置(一定要在 app.use(router) 之前配置)
app.use(session({
    secret:"keyboard cat",
    resave:false,
    saveUninitialized:true
}))
12.3 使用
// 使用
// 当把这个插件配置好之后,我们就可以通过 req.session 来发访问和设置 session 成员。
// 添加 session 数据: req.session.foo = "bar"
// 访问 session 数据: req.session.foo
13 express 中的中间件

http://www.expressjs.com.cn/resources/middleware.html

​ 中间件的本质就是一个请求处理方法,我们把用户从请求到响应的整个过程分发到多个中间件中去处理,这样做的目的是提高代码的灵活性,动态可扩展的。(同一个请求所经过的中间件都是同一个请求对象和响应对象。)

13.1 应用程序级别中间件

万能匹配(不关心任何请求路径和请求方法):

app.use(function(req,res,next){
    console.log("Time",Date.now())
    next() // 若存在 next(), 则会继续执行下面的app.use(); 若不存在,则不执行下面的代码。
})

只执行匹配的 /xxx/ 开头的:

// 只执行以 /a 开始的
app.use("/a",function(req,res,next){
    console.log("Time",Date.now())
    next()
})
13.2 路由级别中间件

get:

app.get('/',function(req,res){
    res.send("Hello World")
})

post:

app.post('/',function(req,res){
    res.send("Hello World.")
})

put:

app.put('/',function(req,res){
    res.send("Hello World.")
})

delete:

app.delete('/',function(req,res){
    res.send("Hello World.")
})
13.3 错误处理中间件
app.use(function(err,req,res,next){
    console.error(err.stack)
    res.status(500).send("something broke!")
})
13.4 第三方中间件

http://www.expressjs.com.cn/resources/middleware.html

13.5 中间件的案例
// 中间件本身是一个方法,该方法接收三个参数。
	// request 请求对象
	// response 响应对象
	// next 下一个中间件
app.use(function(req,res,next){
    console.log(1);
    next()
})

app.use(function(req,res,next){
    console.log(2);
})

app.use(function(req,res,next){
    console.log(3)
})
// 最终输出结果:1 2
// 当请求进来时,会从第一个中间件开始进行匹配,如果匹配,则执行里面的代码;如果不匹配,则继续判断匹配下一个中间件。如果请求进入中间件之后,如果没有调用 next(); 则代码会停在前中间件。如果调用了 next() 则继续向后找到,则继续向后找到第一个匹配的中间件。如果最终也没有找到匹配的中间件,则 Express 会默认输出: Cannot GET 路径。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值