Node.js基础
1.Node.js前言
- Node.js之父:Ryan Dahl(瑞安达尔)
(1)Node出现的背景
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151559976.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
② 性能问题简单来说就是,由于发送请求到接收到响应的时间太长而出现的一些问题。
③ 缩短发送到响应的时长的方法:
1.发送请求快一点(不能控制,因为是由客户端的网速决定的)
2.响应快一点(可以控制,可以通过提高服务器带宽或利用CDN加速等方法实现,但是有限制,不可能无限加快)
3.服务器处理请求任务快一点:(1)可以控制,取决于程序员的技术;(2)多线程(发送一个请求就开启一条线程)
4.服务器从磁盘读取/写入数据到数据库快一点,可以通过分布式、矩阵式、刀片式等方法提高速度。但因为磁盘的读取速度都是有上限的,所以后期都会遇到瓶颈,都会遇到I/O阻塞。
- Ryan Dahl为了解决I/O阻塞,尝试用Ruby、c、Lua去解决,但都因为语言自身的各种限制(语言的历史包袱太重;各种语言的思想都根深蒂固,生态很难改变等)而一一失败。最终通过慢慢摸索,找到了解决问题的方法:事件驱动和异步I/O(V8引擎就满足这两个特性,所以V8引擎的出现是至关重要的)。
(2)V8引擎
-
V8引擎的定义:V8引擎是一款专门对JavaScript语言进行解释和执行的流程虚拟机。比如:如果把V8引擎嵌入到浏览器中,那么JavaScript代码就会被浏览器所执行;如果把V8引擎嵌入到NodeJS环境下,那么JavaScript代码就会被服务器所执行。(万能的JS的定义:主要把V8引擎能够嵌入到不同的宿主环境中,那么就可以用JavaScript语言来写各种不同领域的应用。)
-
V8引擎起初的作用:用于Chrome浏览器解析js脚本。
-
V8引擎的优势:
① 强大的编译和快速执行效率。(因为运用了大量的算法和奇技淫巧)
② 性能非常好,它的执行效率远超Python、Ruby等其它脚本语言。
③ 历史包袱轻,没有同步I/O。
④ 强大的事件驱动机制。
- Node的诞生:Ryan Dahl修改了V8引擎的内核,把它用在了服务器开发,经过修改后的这样一套东西就被称为Node.js(简化版的Node.js,它只是为了解决Web服务器的性能问题)。
2.Node.js简介
(1)什么是Node.js
-
Node.js是一个让JavaScript运行在服务器端的开发平台。
Node.js该开发平台的演化过程:
① Node之前,js代码只能运行在客户端。
② Node之后,js代码可以和操作系统(Mac OS,windows,Linux…)交互,战场从浏览器延伸到服务器。
③ 版本的变化表如下所示:
Node一开始是叫做Web.js,目的就是用于写高性能Web服务器的,后来越写越大,逐渐形成自己的生态(服务器开发,各种框架的依赖…),因此改名为Node.js。
时间节点 |
发生的事件 |
2009年 |
瑞安达尔在GitHub上发布Node的初始版本 |
2010年1月 |
Node包管理器NPM上线 |
2010年12月 |
Joyent赞助Node开发,瑞安达尔加入全力负责Node开发 |
2011年7月 |
与微软合作,发布了Node的Windows版本 |
2012年1月 |
瑞安达尔退出Node团队 |
2014年12月 |
Fedor Indutuy开源分支版本,起名为“io.js” |
2015年1月 |
Node基金会成立(IBM,Intel,微软,Joyent) |
2015年9月 |
Node.js和io.js合并 |
2016年 |
Node.js第6.0版本发布 |
2017年 |
Node.js第8.0版本发布 |
2018年 |
Node,js第8.x同步更新 |
2019年 |
… |
-
Node.js与其它后端语言(PHP、JSP、Python、Ruby等)功能类似,都能和系统进行交互。
-
Node.js与其它后端语言的区别:
① Node.js不是一种独立的语言,它只是一个开发平台。并且它是用JavaScript进行编程,运行平台是包装后的js引擎(V8)。而其它后端语言,像PHP、JSP…语言,它们既是语言,也是平台。
② Node.js是轻量级架构,它不用架设在任何服务器软件(Web容器)上,它可以用最小的硬件成本,达到更高的并发,更优的处理性能。而其它后端语言,像Java、PHP、.net等都需要运行在服务器(apache、tomcat、naginx、IIS等)上。
(2)Node.js的特点
① 单线程。
优势:减少了内存开销(操作系统完全不再有线程创建、销毁的时间开销)。在Java、PHP或者.net等服务器语言中,会为每一个客户端连接创建一个新的线程,而每个线程需要耗费大约2MB内存,相当于有一个人就需要分配一个线程,就要占用空间大小。而Node.js不会为每个客户端连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就会触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
劣势:如果某一个事情进入了,但是被I/O阻塞了,那么整个线程也会被阻塞;如果一个人把Node.js搞崩溃,那么全部都将崩溃(虽然实际是很难搞崩溃的)。
② 非阻塞I/O。
当在访问数据库取得数据的时候,可能需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库的返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。在阻塞模式下(即传统处理方法),一个线程只能处理一项任务,要想提高吞吐量必须通过多线程;而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。Node.js中就是采用了非阻塞I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
③ 事件驱动。
基本概念:不管是新用户的请求,还是老用户的I/O完成,都将以事件方式加入事件环,等待调度。
运作流程:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151709721.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
注意:Node.js当中的所有I/O都是异步的,都是回调函数套回调函数。
(3)Node.js的应用方向
-
特点:
① 善于I/O,不善于计算。
因为Node.j最擅长的就是任务调度,如果业务中有很多CPU计算,实际上也相当于这个计算阻塞了这个单线程,就不适合Node开发;如果应用程序需要处理大量并发的I/O,并且在向客户端发出响应之前,应用程序内部并不需要进行非常复杂的处理的时候,Node.js就非常适合。Node.js也非常适合与web socket配合,开发长连接的实时交互应用程序。
② 天生异步。
callback:Node.js API与生俱来就是这样的。
thunk:参数的求值策略。
promise:最开始上Promise/A+规范,随后成为ES6标准。
generator:ES6中的生成器,用于计算,但tj想用做流程控制。
co:generator用起来非常麻烦,故而tj写了co这个generator生成器用法更简单。
async函数。
-
适用场景:
网站开发(如express/koa等)
im即时聊天(socket.io)
api(移动端、pc、h5)
HTTP Proxy(淘宝、Qunar、腾讯、百度都有)
前端构建工具(grunt/gulp/bower/webpack/fis3…)
跨平台打包工具
写操作系统(NodeOS)
命令行工具(比如cordova、shell.js)
反向代理(比如anyproxy、node-http-proxy)
编辑器Atom、VSCode等
…
-
Node.js不是全能的。
Node.js本身就是极客追求性能极致的产物,缺少了很多服务器的健壮考量,所以Node不可能应用在银行、证券、电信等需要极高可靠性的业务中。而在中国的企业实战中,创业型公司(正处于A轮、B轮)非常喜欢使用Node做核心业务。
-
在大企业中使用的场景:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151801251.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
客户端与服务器
1.CS与BS
-
CS和BS是软件使用方式上的两种划分。
-
C/S(Client/Server):即PC客户端、服务器架构。
特点:在服务器当中最主要的是一个数据库,把所有的业务逻辑以及界面都交给客户端完成。
优点:较为安全,用户界面丰富,用户体验好。
缺点:每次升级都要重新安装,要针对不同的操作系统开发,可移植性差。
-
B/S(Browser/Server):即浏览器/服务器架构。
特点:B/S是基于浏览器访问的应用,它把业务层交给服务器来完成,客户端仅仅做界面的渲染和数据的交换。
优点:只开发服务器端,可以跨平台、移植性很强。
缺点:安全性比较低,用户体验较差。
2.Web资源
-
Web资源的定义:表示网络主机上供外界访问的资源。
-
Web资源的分类:
① 静态Web资源:指web页面中供人们浏览的数据始终是不变的。
② 动态Web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。
-
Web资源的存放位置:所有的web资源都放在一个web服务器当中。其中,web服务器就是可以供外界访问web资源的一个软件,比如:apache、tomcat等。而web资源只要放到指定的目录当中,就可以通过对应的端口在浏览器当中访问到。
-
URL地址:协议://主机地址:端口号/资源地址,比如:http://www.bin.com:80/index.html
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151912235.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
3.资源访问流程
-
客户端:浏览器、Android程序、iOS程序、微信小程序。
-
服务器:php服务器、tomcat服务器、nodeJS服务器…。
-
通过浏览器访问一个网址时,能看到一个页面的原因:
一个网址对应的其实就是一个IP地址(通过DNS),而一个IP地址对应一台电脑。所以通过IP地址就可以找到对应的电脑,电脑中安装有web服务器(可能有多个,比如:同时安转了apache和tomcat),通过端口号就可以找到对应的服务器。找到对应的服务器后,服务器就可以把页面返回给客户端。
-
BS结构流程图(http请求过程):
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151954714.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
Http协议
1.什么是协议
2.什么是HTTP协议
- HTTP(超文本传输协议):是互联网上应用最为广泛的一种网络协议,所有的www文件都必须遵守这个标准,比如:http:www.baidu.com。
- 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。后来结果不断的修正和完善,逐渐变成约束请求和响应的规则。
3.HTTP的组成部分
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623152025292.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
4.请求的发送方式
① 通过浏览器的地址栏
② 通过html当中的form表单
③ 通过a链接的href
④ src属性
5.Http请求
-
请求行
① 请求方式:POST或GET
② 请求资源:如:/request/index.html?username=andy&pwd=123
③ 协议版本:HTTP/1.0和HTTP/1.1。
HTTP/1.0,发送请求,创建一次连接,获得一个web资源,连接断开。
HTTP/1.1,发送请求,创建一次连接,获得多个web资源,保持连接。
-
请求头
① 请求头是客户端发送给服务器端的一些信息。
② 使用键值对表示key:value。
③ 自动的把客户端的信息发送给服务器。
-
请求体
当请求方式是post时,请求体会有请求的参数;当请求方式是get时,请求参数不会出现在请求体中,会拼接在url地址后面。
-
示意图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623152113859.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
6.Http响应
-
响应行
① Http协议(协议版本)
② 状态码:
200:请求成功
302:请求重定向
304:请求资源没有改变,访问本地缓存
404:请求资源不存在。通常是用户路径编写错误,也可能是服务器资源已删除
500:服务器内部错误。通常程序抛异常
③ 其它状态码:200~300之间的代表成功;300~400之间的代表重定向;400~500之间的代表客户方错误;500以上的代表服务器错误。
-
响应头
① 服务器将信息以键值对的形式返回给客户端。
② 自动的把服务器端的信息传给客户端。
-
响应体
响应体是服务器回写给客户端的页面正文。浏览器接收到该页面正文后会把它加载到内存中,然后在解析渲染到页面上。
-
示意图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020062315215438.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
7.请求方式
-
8种请求类型:
① OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性。
② HEAD:请求指定的页面信息,并返回头部信息。
③ GET:请求指定的页面信息,并返回实体主体。
④ POST:向指定资源提交数据进行处理请求。
⑤ PUT:向指定资源位置上传其最新内容。
⑥ DELETE:请求服务器删除Request-URL所标识的资源。
⑦ TRACE:回显服务器收到的请求,主要用于测试或诊断。
⑧ CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
-
常用的2种请求:
(1)GET:
① GET方法向页面请求发送参数
② 地址和参数信息中间用?字符分隔。比如:http://www.baidu.com/hrllo?username=andy&pwd=123
③ 查询字符串会显示在地址栏的URL中,不安全,请不要使用GET请求提交敏感数据
④ GET方法有大小限制:请求字符串中最多只能有1024个字符
⑤ GET请求能够被缓存
⑥ GET请求会保存中浏览器的浏览记录中
⑦ 可以添加书签
⑧ 编码类型为application/x-www-form-urlencoded
⑨ 只允许ASCII字符类型,不能用二进制流
⑩ 点击刷新,不会有反应
⑪ GET请求主要用于获取数据
(2)POST:
① POST方法向页面请求发送参数
② 使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一起发送到服务器
③ 编码类型为:application/x-www-form-urlencoded or multipart/form-data,请为二进制数据使用multipart编码
④ 没有历史记录
⑤ 参数类型没有限制,可以是字符串,也可以是二进制流
⑥ 数据不会显示在地址栏中,也不会缓存下来或保存在浏览记录中,所以POST请求比GET请求安全,但也不是最安全的方式。如需要传送敏感数据,请使用加密方式传输
⑦ 查询字符串不会显示在地址栏中
⑧ POST传输的数据量大,可以达到2M;而GET方法由于受到URL长度限制,只能传递大约1024字节
⑨ POST就是为了将数据传送到服务器端;而GET就是为了从服务器端获取数据
node.js基础
1.命令行窗口
(1)简介
- 命令行窗口是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。它也被称为字符用户界面(CUI)、终端、CMD窗口、shell…。
- 命令行窗口可以同时开启多个,并且它们之间是不会互相影响的。
(2)常用命令讲解
① dir:列出当前目录下面所有的文件。
② cd 目录名:进入到指定的目录,比如:cd Desktop(进入桌面)。.当前目录,…进入上级目录,比如:cd .(当前目录);cd …(上级目录)。
③ md 目录名:创建文件夹。
④ rd 目录名:删除文件夹。
⑤ cd.>文件名.后缀名:创建文件,比如:cd.>a.txt。
⑥ cls:清屏。
⑦ exit:退出命令行。
2.进程和线程
(1)进程
- 概念:进程是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
- 进程为程序的运行提供了必备的环境,所以代码和程序都是放在进程里面,它相当于工厂中的车间。
(2)线程
- 概念:线程是计算机中最小的计算单位,它负责执行进程中的程序,相当于车间中的操作工人。
- 分类:线程可以分为单线程(js就是单线程)和多线程(它可以根据任务决定开启几条线程)。
3.安装node.js
- 直接去官网下载,安转过程中直接下一步。
- 安装完成后,会自动配置好环境变量。配置好环境变量后,就可以在任何一个目录当中访问node命令(即配置成一个全局的环境变量)。如果系统没有自动配置环境变量,那么就要手动进行配置,配置过程:右击我的电脑——>点击属性——>点击高级系统配置——>点击高级,然后点击环境变量——>在系统变量中打开Path,并新建一条记录(node安装的位置,比如:c:\Program Files\node.js\)。
- 在控制台通过node -v可以查看node 版本。
4.node如何运行js程序
- 可以在命令行窗口运行js程序(包括:直接在命令行窗口书写js代码然后运行或者在命令行窗口通过node xxx.js运行js文件);也可以在编辑器上运行js程序,如:VSCode、WebStorm等。
5.Node的模块化开发思想
-
在ES6之前,ECMAScript存在以下几个问题:
(1)没有模块系统
(2)官方标准库少/标准接口少
(3)缺乏包管理系统
-
模块化:如果程序设计的规模达到了一定的程度,则必须对其使用模块化。
(1)前端只是进行页面的渲染,数据的请求及传输等,所以不太需要模块化
(2)服务器端端开发,如果没有模块化思想就很难进行开发
(3)模块化可以有多种形式,但都提供了能够将代码分隔为多个源文件的机制。如:Common.js
-
CommonJS规范:
(1)CommonJS规范等提出,主要是为了弥补JavaScript没有模块化标准的缺陷。
(2)CommonJS对模块的定义:
① 模块引用:require(“路径”);
② 模块定义
③ 模块标识
-
总结:
(1)从文件的角度看,每个JS文件就是一个模块;从结构看,多个JS文件之间可以相互require,共同实现一个功能,这整体上也是一个模块。
(2)在Node.js中,一个模块中定义的变量、函数等,都只能在这个文件等内部有效;当需要从此JS文件的外部引用这些变量、函数时,就必须使用exports进行暴露,使用者通过require进行引用。
-
实践1:
//one.js
let str = "Hello!";
let test = () => {
console.log("今天你跑步了吗?");
}
exports.str = str;
exports.test = test; //不能加小括号
//two.js
let fn = require('./one.js'); //必须添加.或者..,具体看引用的文件的位置
console.log(fn.str);
fn.test();
(1)如果一个js(one.js)文件引用了其他js(other.js)文件,然后另一个js(two.js)文件又引用了该js(one.js)文件,那么该js(two.js)文件不仅可以使用所引用的js(one.js)文件,还可以使用所引用的js(one.js)文件中引用的js(other.js)文件。
(2)在Node中,一个js文件就是一个模块。
(3)在Node中,通过require()函数来引入外部的模块。注意,引入外部模块时,其路径要加上.或者…。比如:当前目录就是./xxx;上一级目录就是./…/xxx。
(4)在Node中,每一个js文件中的js代码都是独立运行在一个小闭包中,而不是全局作用域,所以一个模块中的变量和函数在其他模块中无法访问。它的目的就是:使全局变量私有化,避免全局污染。
(5)在Node中,通过exports暴露模块中的变量和函数时,只需要将需要暴露给外部的变量或方法设置为exports的属性即可。
(6)练习:封装一个myFunc(能够进行求和、求平均数)。
//myFunc.js
exports.sum = (...numbers) => {
let result = 0;
numbers.forEach((item) => {
result += item;
});
return result;
};
exports.avg = (...numbers) => {
let result = 0;
numbers.forEach((item) => {
result += item;
});
return result / numbers.length;
};
//one.js
//文件模块
let func = require("./js/myFunc"); //路径可以带后缀名,也可以不带后缀名,系统都会自动补充完整
console.log(func); //其实,这个func就是exports,所以输出结果为:{sum:[Function], avg:[Function]}
console.log(func.sum(1,2,3,4)); //输出结果为:10
console.log(func.avg(1,2,3,4)); //输出结果为:2.5
//核心模块
let http = require("http");
(1)模块标识
① 当使用require()引入外部模块的时候,使用的就是模块标识。通过模块标识可以找到指定的模块。
② 模块的分类:
内建模块:底层由C++编写,所以底层的模块都是内建模块。
文件模块:由用户自己创建的模块。其标识是:文件的路径(绝对路径、相对路径)。
核心模块:由node引擎提供的模块以及由node_modules提供的模块。其标识是:模块的名字,比如:http、fs、global…。
(2)exports和require的由来
-
Node中的全局对象不是window,而是global,它的作用类似window。
console.log(window.exports); //报错
console.log(global.exports); //undefined
-
exports和require不是全局变量,而是函数参数。(Node会在每个js文件的外面套上一个闭包函数)
-
函数的标识:arguments(作用:获取函数的所有实参,是一个伪数组);
arguments.callee(作用:返回函数本身)
console.log(arguments.callee); //输出结果为:[Function],如果想要看函数里面的内容,可以把它转换为字符串(通过:arguments.callee + "")
(3)node文件组成剖析
① 当node在执行模块中的代码时,它会首先在代码的最顶部添加如下代码:
function (exports, require, module, __filename, __dirname){
② 在代码的最底部,添加}
③ 所以模块中的代码都是包装在一个函数中执行的,并且在函数执行的同时传递了5个实参。
exports:该对象用来将函数内部的局部变量或局部函数暴露到外部。(函数的执行顺序是从上往下执行,所以一个模块中如果重复暴露同一个变量多次,那么以最后一次暴露的变量值为准)
require:用来引入外部的模块。
module:代表的是当前模块本身(module是一个对象)。exports就是module的属性,所以既可以使用exports导出,也可以使用module.exports导出。
console.log(exports); //输出结果为:{}
console.log(module.exports); //输出结果为:{}
//没有暴露或暴露错误或没有引入外部模块或引入错误等,都是直接在控制台中打印一个空对象,不会报错。
__filename:当前模块的完整路径(精确到当前文件名),如C:\Users\bin\Desktop\test\one.js。
__dirname:当前模块所在文件夹的完整路径(只精确到当前文件所在的文件夹名),如:C:\Users\bin\Desktop\test。
6.exports和module.exports的区别
let md = new Object();
md.exp = new Objext({
name:'andy'});
let exp = md.exp; //这就是exports和module.exports建立的联系。如果此时给exports赋值一个对象,那么这种联系就会断开。所以,为了保持它们之间的这种联系,不能给exports赋值一个对象。
exp.name = "Mary";
console.log(exp.name); //输出结果为:Mary
console.log(md.exp.name); //输出结果为:Mary
//Person.js
function Person(name,age,sex){
this.name = name;
this,age = age;
this.sex = sex;
}
Person.prototype = {
play: function(){
console.log(this.name + '去打篮球了!');
}
};
//因为构造函数或类都是对象(JS中万物皆对象),所以这里只能用module.exports将该类导出。
module.exports = Person;
//one.js
let Person = require('./Person');
let p = new Person("andy",22,"男");
console.log(p); //输出结果为:{name:'andy', age:22,sex:'男'}
7.包和包管理器
(1)包
-
概念:ConmonJS的包规范允许我们将一组相关的模块组合到一起,形成一组完整的工具,这组工具就叫做包。
-
组成:
① 包结构。它用于组织包中的各种文件,实际上就是一个压缩文件,解压以后还原为目录,该目录包括:package.json(描述文件)、bin(可执行二进制文件)、lib(js代码)、doc(文档)、test(单元测试)。
② 包描述文件-package.json。它描述了包的相关信息,以供外部读取分析。同时,它是一个JSON格式的文件,位于包的根目录下。
-
注意:package.json文件中,不能加入任何注释。
(2)包管理器(NPM)
-
概念:NPM,即Node Package Manager,它的作用相当于360管家。对于Node而言,NPM帮助其完成了第三方模块的发布、安装和依赖等。借助NPM,Node与第三方模块之间形成了很好的一个生态系统。
-
常用命令:
① npm -v:查看版本
② npm version:查看所有模块的版本
③ npm search 包名/部分包名:搜索包
④ npm init:初始化package.json文件
⑤ npm install/i 包名:安装包
⑥ npm remove/r 包名:删除包
⑦ npm install/i 包名 --save:安装包并添加到依赖中
⑧ npm install:根据package.json下载当前项目所依赖的包
⑨ npm install 包名 -g:全局安装包,用于一些编译根据,比如:gulp、webpack等
注意:如果在页面中引入node_modules中某个模块,优先从当前目录引入,如果没有,则往上级查找,直到根目录。
(3)CNPM
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623152351672.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMDA2OQ==,size_16,color_FFFFFF,t_70#pic_center)
node.js基础-文件系统
1.Buffer(缓冲区)
-
为什么要用Buffer?
(1)在Node、ES6出现之前,前端工程师只需要进行一些简单的字符串或DOM操作就可以满足业务需要,所以对二进制数据是比较陌生的。
(2)但在Node出现之后,前端工程师面对的技术场景发生了变化,可以深入到网络传输、文件操作、图片处理等领域,而这些操作都与二进制数据紧密相关。
(3)Node里面的buffer,是一个二进制数据容器,数据结构类似于数组,专门用于Node中数据的存放。
-
Buffer的基本使用
(1)历史使用方式:
cosnt buf1 = new Buffer(10); //10表示Buffer的长度
console.log(buf1); //输出结果为:<Buffer 00 00 00 00 00 00 00 00 00 00>
这种方式在分配的内存中可能还存储着旧数据,所以存在安全隐患。(现在已经被废弃了)
(2)新使用方式:
Buffer提供了Buffer.from、Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlow四个方法来申请内存。
① Buffer.from(string[,encoding]):将一个字符串转换为buffer(二进制)。其中,string是要编码的字符串;encoding是string的字符编码,默认为:‘utf-8’。
let str = "www.baidu.com"; //一个字母在Buffer中占一个字节,比如:w在Buffer中就变成77
let buffer = Buffer.from(str);
console.log(buffer);
console.log(buffer.toString()); //转换为十进制,又变成www.baidu.com
console.log(str.length); //输出结果为:13
console.log(buffer.length); //输出结果为:13
let str1 = "你好";
let buffer = Buffer.from(str1);
console.log(str.length); //输出结果为:2
console.log(buffer.length); //输出结果为:6
//一个汉字在Buffer中占3个字节
② Buffer.alloc(size[,fill[,encoding]]):创建一个指定大小的Buffer。其中,size是新建的Buffer期望的长度,确定之后不能动态的改变;fill是用来预填充新建的Buffer的值,可以是string、Buffer、integer,默认为:0;encoding意思是:如果fill是字符串,则该值是它的字符编码,默认为:‘utf-8’。
let buffer = Buffer.alloc(10);
console.log(buffer); //输出结果为:<Buffer 00 00 00 00 00 00 00 00 00 00>
buffer[0] = 10; //跟数组一样,也可以通过下标获取或赋值
console.log(buffer); //输出结果为:<Buffer 0a 00 00 00 00 00 00 00 00 00>
buffer[1] = 0xfc; //直接传入一个十六进制,输出就不会进行转换,因为本来输出就是十六进制
console.log(buffer); //输出结果为:<Buffer 0a fc 00 00 00 00 00 00 00 00>
buffer[11] = 20; //赋值操作超过Buffer的长度,所以不会进行处理
console.log(buffer); //输出结果为:<Buffer 0a fc 00 00 00 00 00 00 00 00>
//Buffer也能够跟数组一样使用forEach进行遍历处理
buffer.forEach((item,index) => {
console.log(index +":" + item);
});
③ Buffer.allocUnsafe(size):创建一个指定大小的Buffer,但是可能包含敏感数据。
注意:Buffer是一个核心模块,但它不需要引入,可以直接使用。
(3)Buffer使用的相关注意点:
① Buffer的结构和数组很像,操作的方法也和数组类似。
② Buffer中是以二进制的方式存储数据的。
③ Buffer是Node自带的,不需要引入,直接使用即可。
2.文件系统(File System)
(1)基本概念
① 在Node中,与文件系统的交互是非常重要的,服务器的本质就是将本地的文件发送给远程的客户端。
② Node通过fs模块与文件系统进行交互,该模块提供了一些标准文件访问API来打开、读取、写入文件,以及与其交互。
③ 使用fs模块之前,要先从核心模块中加载:const fs = require(“fs”);。
//同步文件写入:
//引入模块
let fs = require("fs");
//打开文件
//打开文件的两个类方法:异步:fs.open(path,flags[,mode],callback)、同步:fs.openSync(path,flags[,mode])。其中,flags是一个标识,比如:r就是读;w就是写。
let fd = fs.openSync("one.txt","w");
//写入内容
//写入文件的两个类方法:异步:fs.writeFile(file,data[,options],callback)、同步:fs.writeFileSync(file,data[,options])。其中,file是文件名;data是传入的数据;options包括encoding、mode、flag(默认是:'w'),它一般都是默认值就好。
fs.writeFileSync(fd,"Hello World!");
//保存并退出
//退出有两个类方法:异步:fs.close(fd,callback)、同步:fs.closeSync(fd)
fs.closeSync(fd);
(2)使用特点
① fs模块中所有的操作都有两种形式可供选择(同步和异步)。
② 同步文件系统会阻塞程序的执行,也就是除非操作完毕,否则不会向下执行代码。
③ 异步文件系统不会阻塞程序的执行,而是在操作完成时,通过回调函数将结果返回。
(3)文件操作
① 打开文件:fs.open(path,flags[,mode],callback)、fs.openSync(path,flags[,mode])。其中,callback有两个参数,分别是err和fd,fd代表读写的那个文件。
flags取值 |
说明 |
r |
读取文件,文件不存在则出现异常 |
r+ |
读写文件,文件不存在则出现异常 |
rs |
在同步模式下打开文件用于读取 |
rs+ |
在同步模式下打开文件用于读写 |
w |
打开文件用于写操作,如果不存在则创建,如果存在则截断 |
wx |
打开文件用于写操作,如果存在则打开失败 |
w+ |
打开文件用于读写,如果不存在则创建,如果存在则截断 |
wx+ |
打开文件用于读写,如果存在则打开失败 |
a |
打开文件用于追加,如果不存在则创建 |
ax |
打开文件用于追加,如果路径存在则失败 |
a+ |
打开文件用于读取和追加,如果不存在则创建该文件 |
ax+ |
打开文件进行读取和追加,如果路径存在则失败 |
② 关闭文件
③ 写入文件操作
④ 读取文件操作
//异步文件写入:
//引入模块
let fs = reqire("fs");
//打开文件
fs.open("one.txt","w",(err,fd) => {
//判断是否出错
if(!err){
//写入文件
//fs.writeFile(file,data[,options],callback)中的callback有一个形参err
fs.writeFile(fd,"你好!",(err) => {
//写入成功
if(!err){
console.log("写入文件成功");
}else{
throw err;
}
//关闭文件
//fs.close(fd,callback)中的callback有一个形参err
fs.close(fd,(err) => {
if(!err){
console.log("文件已经保存并关闭!");
}
})
});
}else{
throw err;
}
})
//异步都是回调嵌套回调
//异步没有返回结果,结果都是通过回调函数返回
//异步是node的一个特色,它不会阻塞线程。如果一个线程发生了错误,后面的程序也会照样执行
//文件流式写入
//引入模块
let fs = require("fs");
//创建写入流
//fs.createWriteStream(path[,options]),该方法是同步的。其中,options是一个对象,包括flags、encoding、fd、mode、autoClose和start。
let ws = fs.createWriteStream("one.txt");
//打开通道
//通过“close”事件或“open”事件关闭或打开通道
ws.once("open", () => {
console.log("通道已经打开!");
});
ws.once("close", () => {
console.log("通道已经关闭!");
});
//写入内容
ws.write("Good Morning!");
ws.write("Good Afternoon!");
ws.write("Good Evening!");
//关闭通道
ws.end();
//读取文件:
//引入模块
let fs = require("fs");
//举例1:读取文本文件
//fs.readFile(path[,options],callback),其中,options是一个对象,包括encoding(默认为:null)和flag(默认为:r)两个属性;callback有两个形参,分别是err和data(string|Buffer)。
fs.readFile("one.txt",(err,data) => {
//判断
if(!err){
console.log(data); //二进制
console.log(data.toString()); //十进制
}else{
throw err;
}
});
//举例2:读取并写一张图片
fs.readFile("C:/Users/bin/Desktop/bg.jpg",(err,data) => {
//路径也可以写成:C:\\Users\\bin\\Desktop\\bg.jpg
//判断
if(!err){
//写入图片文件
fs.writeFile("img.jpg",data,(err) => {
if(!err)
console