Node.js知识概括
操作系统知识
命令行:
-
开始菜单 --> 运行 --> CMD --> 回车
-
常用的指令:
①dir 列出当前目录下的所有文件
②cd 目录名 进入到指定的目录
③md 目录名 创建一个文件夹
④rd 目录名 删除一个文件夹 -
目录:
①. 表示当前目录
②.. 表示上一级目录
-
环境变量(windows系统中变量)
①path
C:\work\jdk\jdk1.7.0_75/bin;
%CATALINA_HOME%/bin;
C:\work\soft\tools\AppServ\Apache24\bin;
C:\work\soft\tools\AppServ\php5;
C:\Users\lilichao\AppData\Local\Programs\Fiddler;
C:\work\environment\Egret\Egret Wing 3\bin;
C:\Users\lilichao\AppData\Roaming\npm;
C:\Program Files\MongoDB\Server\3.2\bin;
C:\Users\lilichao\Desktop\hello
- 当我们在命令行窗口打开一个文件,或调用一个程序时,系统会首先在当前目录下寻找文件程序,如果找到了则直接打开,如果没有找到则会依次到环境变量path的路径中寻找,直到找到为止,如果没找到则报错。
- 所以我们可以将一些经常需要访问的程序和文件的路径添加到path中,这样我们就可以在任意位置来访问这些文件和程序了。
IO和cpu和内存和Node:
- I/O (Input/Output):I/O操作指的是对磁盘的读写操作
- Node
①Node是对ES标准一个实现,Node也是一个JS引擎
②通过Node可以使js代码在服务器端执行
③Node仅仅对ES标准进行了实现,所以在Node中不包含DOM 和 BOM
④Node中可以使用所有的内建对象
<1>String Number Boolean Math Date RegExp Function Object Array
<2>而BOM和DOM都不能使用
<3>但是可以使用 console 也可以使用定时器(setTimeout() setInterval()) - Node可以在后台来编写服务器:Node编写服务器都是单线程的服务器
进程:进程就是一个一个的工作计划(工厂中的车间)。
<1>代表内存线程:线程是计算机最小的运算单位(工厂中的工人),线程是干活的。
<1>代表CPU传统的服务器都是多线程的:每进来一个请求,就创建一个线程去处理请求
Node的服务器单线程的:Node处理请求时是单线程,但是在后台拥有一个I/O线程池。
Node.js简介
Node.js简介:
- Node.js是一个能够在服务器端运行JavaScript的开放源代码、 跨平台JavaScript运行环境。
- Node采用Google开发的V8引擎运行js代码,使用事件驱动、非阻塞和异步I/O模型等技术来提高性能,可优化应用程序的传输量和规模。
- Node大部分基本模块都用JavaScript编写。在Node出现之前,JS通常作为客户端程序设计语言使用,以JS写出的程序常在用户的浏览器上运行。
- 目前,Node已被IBM、Microsoft、Yahoo!、Walmart、Groupon、SAP、 LinkedIn、Rakuten、PayPal、Voxer和GoDaddy等企业采用。
Node.js作用:
- Node主要用于编写像Web服务器一样的网络应用,这和PHP 和Python是类似的。
- 但是Node与其他语言最大的不同之处在于,PHP等语言是阻塞的而Node是非阻塞的。
- Node是事件驱动的。开发者可以在不使用线程的情况下开发出一个能够承载高并发的服务器。其他服务器端语言难以开发高并发应用,而且即使开发出来,性能也不尽人意。
- Node正是在这个前提下被创造出来。
- Node把JS的易学易用和Unix网络编程的强大结合到了一起
Node.js具体作用:
- Node.js允许通过JS和一系列模块来编写服务器端应用和网络 相关的应用。
- 核心模块包括文件系统I/O、网络(HTTP、TCP、UDP、DNS、TLS/SSL等)、二进制数据流、加密算法、数据流等等。Node模块的API形式简单,降低了编程的复杂度。
- 使用框架可以加速开发。常用的框架有Express.js、Socket.IO和Connect等。Node.js的程序可以在Microsoft Windows、Linux、Unix、Mac OS X等服务器上运行。
- Node.js也可以使用CoffeeScript、TypeScript、Dart语言,以及其他能够编译成JavaScript的语言编程。
Node.js开发者:
- 瑞安·达尔(Ryan Dahl)Ryan Dahl并非科班出身的开发者,在2004年的时候他还在纽 约的罗彻斯特大学数学系读博士。
- 2006年,也许是厌倦了读博的无聊,他产生了『世界那么大, 我想去看看』的念头,做出了退学的决定,然后一个人来到智利的Valparaiso小镇。
- 从那起,Ryan Dahl不知道是否因为生活的关系,他开始学习 网站开发了,走上了码农的道路。
- 那时候Ruby on Rails很火,他也不例外的学习了它。
- 从那时候开始,Ryan Dahl的生活方式就是接项目,然后去客户的地方工作,在他眼中,拿工资和上班其实就是去那里旅行。
- Ryan Dahl经过两年的工作后,成为了高性能Web服务器 的专家,从接开发应用到变成专门帮客户解决性能问题的 专家。
- 期间他开始写一些开源项目帮助客户解决Web服务器的高 并发性能问题,他尝试了很多种语言,但是最终都失败了。
- 在他快绝望的时候,V8引擎来了。V8满足他关于高性能 Web服务器的想象。于是在2009年2月它开始着手编写 Node.js
Node的历史:
时间 | 事件 |
---|---|
2009年 | 瑞安·达尔(Ryan Dahl)在GitHub上发布node的最初版本 |
2010年1月 | Node的包管理器npm诞生 |
2010年底 | Joyent公司赞助Node的开发,瑞安·达尔加入旗下,全职负责Node |
2011年7月 | Node在微软的帮助下发布了windows版本 |
2011年11月 | Node超越Ruby on Rails,称为GitHub上关注度最高的项目 |
2012年1月 | 瑞安·达尔离开Node项目 |
2014年12月 | Fedor Indutny在2014年12月制作了分支版本,并起名“io.js” |
2015年初 | Node.js基金会成立(IBM、Intel、微软、Joyent) |
2015年9月 | Node.js和io.js合并,Node 4.0发布 |
2016年 | Node 6.0发布 |
2017年 | Node 8.0发布 |
Node的用途:
- Web服务API,比如REST
- 实时多人游戏
- 后端的Web服务,例如跨域、服务器端的请求
- 基于Web的应用
- 多客户端的通信,如即时通信
Node.js入门
安装NODE.JS:
- 以下的全部点上。
①npm包管理工具。
②添加到环境变量。
安装完成后进入cmd,输入node -v。出现版本号即可。
node目录结构:
COMMONJS规范
ECMAScript标准的缺陷:
- 没有模块系统
- 标准库较少
- 没有标准接口
- 缺乏管理系统
模块化:
- 如果程序设计的规模达到了一定程度,则 必须对其进行模块化。
- 模块化可以有多种形式,但至少应该提供能够将代码分割为多个源文件的机制。
- CommonJS 的模块功能可以帮我们解决该问题。
CommonJS规范:
- CommonJS规范的提出,主要是为了弥补当 前JavaScript没有模块化标准的缺陷。
- CommonJS规范为JS指定了一个美好的愿景,希望JS能够在任何地方运行。
- CommonJS对模块的定义十分简单:
①模块引用
②模块定义
③模块标识
模块引用:
- 在规范中,
定义了require()方法,这个方法接手模块标识,
以此将一个模块引入到 当前运行环境中。 - 模块引用的示例代码:
var math = require('math');
模块定义:
- 在运行环境中,
提供了exports对象用于导出当前模块的方法或者变量,并且它是唯一的导出的出口。
在模块中还存在一个module对象,它代表 模块自身,而exports是module的属性。
- 在Node中一个文件就是一个模块。
默认情况下在js文件中编写的内容,都是运行在一个独立的函数中,外部的模块无法访问
①node底层会给执行的JS代码添加上函数。
②并传入几个参数有module、erports等等。- 示例:
//使用 exports
exports.属性 = 属性值;
exports.方法 = 函数;
//使用module.exports
module.exports.属性 = 属性值;
module.exports.方法 = 函数;
module.exports = {};
JS闭包与IIFE与模块化:
js的作用域分两种,全局和局部
,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的
,那么我们想在一个函数内部也有限权访问另一个函数内部的变量该怎么办呢?- 闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。
- 闭包有3个特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收 - 总结:
①在函数内部创建使用的变量或函数。
②返回一个函数或对象,将需要给外部使用的变量或函数暴露出去。
③函数外部只能访问暴露出去的变量或函数。
④函数内部没有暴露出去的变量或函数,函数外部不可知晓。
模块标识:
模块标识其实就是模块的名字或路径,也就是传递给require()方法的参数,
- 它必须是符合驼峰命名法的字符串,或者是以
.
、..
开头的相对路径、或者绝对路径。 - 模块的定义十分简单,接口也十分简洁。 每个模块具有独立的空间,它们互不干扰, 在引用时也显得干净利落。
- 我们node通过模块的标识来寻找模块的
- 对于核心模块(npm中下载的模块),直接使用模块的名字对其进行引入
var fs = require("fs");
var express = require("express");
- 对于自定义的文件模块,需要通过文件的路径来对模块进行引入,路径可以是绝对路径,如果是相对路径必须以./或 …/开头
var router = require("./router");
Node的模块实现
- Node中虽然使用的是CommonJS规范,但是 其自身也对规范做了一些取舍。
- 在Node中引入模块,需要经历如下3个步骤:
①路径分析
②文件定位
③编译执行
- 在Node中,模块分为三类:
①一类是底层由C++编写的内建模块,
②一类是Node提供的核心模块;
③还有一类是用户编写的模块,称为文件模块。
包 package
包package简介:
- CommonJS的包规范允许我们将一组相关 的模块组合到一起,形成一组完整的工具。
- CommonJS的包规范由
包结构
和包描述
文件两个部分组成。 - 包结构
①用于组织包中的各种文件
- 包描述文件
①描述包的相关信息,以供外部读取分析
包结构:
- 包实际上就是一个压缩文件,解压以后还原为目录。
- 符合规范的目录,应该包含如下文件:
①package.json :描述文件
②bin: 可执行二进制文件
③lib :js代码
④doc :文档
⑤test :单元测试
包描述文件:
- 包描述文件用于表达非代码相关的信息, 它是一个JSON格式的文件 – package.json, 位于包的根目录下,是包的重要组成部分。
- 主要字段:
①name 包名
②version 版本
③dependencies 依赖
④main 包的主要的文件
⑤bin 可执行文件 - package.json中的字段:
name、description、version、keywords、
maintainers、contributors、bugs、
licenses、repositories、dependencies、
homepage、os、cpu、engine、builtin、
directories、implements、scripts、author、
bin、main、devDependencies。
NPM(Node Package Manager)
NPM简述:
- CommonJS包规范是理论,NPM是其中一 种实践。
- 对于Node而言,NPM帮助其完成了第三 方模块的
发布
、安装
和依赖
等。 - 借助NPM,
Node与第三方模块之间形成了很好的一个 生态系统。
NPM命令:
npm –v
– 查看版本npm version
– 查看所有模块的版本npm
– 帮助说明npm search 包名
– 搜索模块包npm install/ i 包名
– 在当前目录安装包npm install 包名 –g
– 全局模式安装包(全局安装的包一般都是一些工具)npm remove / r 包名
– 删除一个模块npm install 包名 --save
– 安装包并添加到依赖中npm install 文件路径
– 从本地安装npm install 包名 –registry=地址
– 从镜像源安装npm config set registry 地址
– 设置镜像源
npm细节详解:
- 下载下来的npm包会放在一个node_modules的目录中。
- 并且以模块名命名目录,package.json和index.js都会放在里面。
①package.json:包描述文件
②index.js:js文件入口。
Buffer(缓冲区)
Buffer(缓冲区):
- 从结构上看Buffer非常像一个数组,它的元 素为16进制的两位数。
- 实际上一个元素就表示内存中的一个字节。
- 实际上Buffer中的内存不是通过JavaScript 分配的,而是在底层通过C++申请的。
- 也就是我们可以直接通过Buffer来创建内存 中的空间。
Buffer的操作:
- 使用Buffer保存字符串
let str = "你好 atguigu";
let buf = Buffer.from(str , "utf-8");
- 创建指定大小的Buffer对象
let buf3 = Buffer.alloc(1024*8)
Buffer的转换:
- Buffer与字符串间的转换
①支持的编码: • ASCII、UTF-8、UTF-16LE/UCS-2、Base64、Binary、Hex - 字符串转Buffer
①Buffer.from(str , [encoding]); - Buffer转字符串
①buf.toString([encoding] , [start] , [end]);
创建操作:
- Buffer.alloc(size)
①创建一个指定大小的buffer对象 - Buffer.allocUnsafe(size)
①创建一个指定大小的buffer对象,可以包含敏感数据
写入操作:
- 向缓冲区中写入字符串
①buf.write(string[, offset[, length]][, encoding]) - 替换指定索引位置的数据
①buf[index] - 将指定值填入到缓冲区的指定位置
①buf.fill(value[, offset[, end]][, encoding])
读取操作:
- 将缓冲区中的内容,转换为一个字符串返回
①buf.toString([encoding[, start[, end]]]) - 读取缓冲区指定索引的内容
①buf[index]
其他操作:
- 复制缓冲区
①buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]) - 对缓冲区切片
①buf.slice([start[, end]]) - 拼接缓冲区
①Buffer.concat(list[, totalLength])
fs(文件系统)
fs简介:
- 在Node中,与文件系统的交互是非常重要 的,服务器的本质就将本地的文件发送给 远程的客户端
- Node通过fs模块来和文件系统进行交互
- 该模块提供了一些标准文件访问API来打开、 读取、写入文件,以及与其交互。
- 要使用fs模块,首先需要对其进行加载 – const fs = require(“fs”);
同步和异步调用:
- fs模块中所有的操作都有两种形式可供选择 同步和异步。
同步文件系统会阻塞程序的执行,也就是 除非操作完毕,否则不会向下执行代码。
异步文件系统不会阻塞程序的执行,而是 在操作完成时,通过回调函数将结果返回。
打开和关闭文件:
- 打开文件
① fs.open(path, flags[, mode], callback)
② fs.openSync(path, flags[, mode]) - 关闭文件
①fs.close(fd, callback)
②fs.closeSync(fd)
打开状态:
模式 | 说明 |
---|---|
r | 读取文件 , 文件不存在则出现异常 |
r+ | 读写文件 , 文件不存在则出现异常 |
rs | 在同步模式下打开文件用于读取 |
rs+ | 在同步模式下打开文件用于读写 |
w | 打开文件用于写操作 , 如果不存在则创建,如果存在则截断 |
wx | 打开文件用于写操作, 如果存在则打开失败 |
w+ | 打开文件用于读写, 如果不存在则创建, 如果存在则截断 |
wx+ | 打开文件用于读写, 如果存在则打开失败 |
a | 打开文件用于追加, 如果不存在则创建 |
ax | 打开文件用于追加, 如果路径存在则失败 |
a+ | 打开文件进行读取和追加, 如果不存在则创建该文件 |
ax+ | 打开文件进行读取和追加,如果路径存在则失败 |
写入文件:
- fs中提供了四种不同的方式将数据写入文件
①简单文件写入
②同步文件写入
③异步文件写入
④流式文件写入
简单文件写入:
- fs.writeFile(file, data[, options], callback)
- fs.writeFileSync(file, data[, options])
- 参数:
①file 文件路径
②data 被写入的内容,可以是String或Buffer
③options 对象,包含属性(encoding、mode、flag)
④ callback 回调函数
同步文件写入:
- fs.writeSync(fd, buffer, offset, length[, position])
- fs.writeSync(fd, data[, position[, encoding]])
- 要完成同步写入文件,先需要通过openSync()打开文件来获取 一个文件描述符,然后在通过writeSync()写入文件。
- 参数
①fd 文件描述符,通过openSync()获取
②data 要写入的数据(String 或 Buffer) – offset buffer写入的偏移量
③length 写入的长度
④position 写入的起始位置
⑤encoding 写入编码
异步文件写入:
- fs.write(fd, buffer, offset, length[, position], callback)
- fs.write(fd, data[, position[, encoding]], callback)
- 要使用异步写入文件,先需要通过open()打开文件,然后在回 调函数中通过write()写入。
- 参数:
① fd 文件描述符
②data 要写入的数据(String 或 Buffer) – offset buffer写入的偏移量
③length 写入的长度
④position 写入的起始位置
⑤encoding 写入编码
流式文件写入:
- 往一个文件中写入大量数据时,最好的方法之一 是使用流。
- 若要将数据异步传送到文件,首需要使用以下语 法创建一个Writable对象:
①fs.createWriteStream(path[, options])
<1>path 文件路径
<2>options {encoding:"",mode:"",flag:""} - 一旦你打开了Writable文件流,就可以使用 write()方法来写入它,写入完成后,在调用end() 方法来关闭流。
读取文件:
- fs中提供了四种读取文件的方式
①简单文件读取
②同步文件读取
③异步文件读取
④流式文件读取
简单文件读取:
- fs.readFile(file[, options], callback)
- fs.readFileSync(file[, options])
- 参数:
①file 文件路径或文件描述符
②options |
③encoding | 默认 = null
④flag 默认 = ‘r’ • callback 回调函数,有两个参数err 、data
同步文件读取:
- fs.readSync(fd, buffer, offset, length, position)
- 参数:
①fd 文件描述符
②buffer 读取文件的缓冲区
③offset buffer的开始写入的位置
④length 要读取的字节数
⑤position 开始读取文件的位置
异步文件读取:
- fs.read(fd, buffer, offset, length, position, callback)
- 参数:
① fd 文件描述符
②buffer 读取文件的缓冲区
③offset buffer的开始写入的位置
④length 要读取的字节数
⑤position 开始读取文件的位置
⑥callback 回调函数 参数err , bytesRead , buffer
流式文件读取:
- 从一个文件中读取大量的数据时,最好的方法之一就是 流式读取,这样将把一个文件作为Readable流的形式 打开。
- 要从异步从文件传输数据,首先需要通过以下语法创建一个Readable流对象:
①fs.createReadStream(path[, options])
<1>path 文件路径
<2>options {encoding:"",mode:"",flag:""} - 当你打开Readable文件流以后,可以通过readable事 件和read()请求,或通过data事件处理程序轻松地从它 读出。
其他操作:
- 验证路径是否存在
① fs.exists(path,callback)
②fs.existsSync(path) - 获取文件信息
①fs.stat(path, callback)
②fs.statSync(path) - 删除文件
①fs.unlink(path, callback)
② fs.unlinkSync(path) - 列出文件
① fs.readdir(path[, options], callback)
②fs.readdirSync(path[, options]) - 截断文件
①fs.truncate(path, len, callback)
②fs.truncateSync(path, len) - 建立目录
① fs.mkdir(path[, mode], callback)
②fs.mkdirSync(path[, mode]) - 删除目录
① fs.rmdir(path, callback)
②fs.rmdirSync(path) - 重命名文件和目录
① fs.rename(oldPath, newPath, callback)
② fs.renameSync(oldPath, newPath) - 监视文件更改写入
① fs.watchFile(filename[, options], listener)
模版引擎
art-template 详解:
- art-template 不仅可以在浏览器使用,也可以在 node 中使用。
- 安装:npm install art-template
①该命令在哪执行就会把包下载到哪里。默认会下载到 node_modules 目录中,node_modules 不要改,也不支持改。 - 使用:在需要使用的文件模块中加载 art-template
①只需要使用 require 方法加载就可以了:require(‘art-template’),
<1>参数中的 art-template 就是你下载的包的名字,也就是说你 isntall 的名字是什么,则你 require 中的就是什么。
② 查文档,使用模板引擎的 API
<1>链接:art-template官方文档 - 注意:
①在浏览器中需要引用 lib/template-web.js 文件
<1>强调:模板引擎不关心你的字符串内容,只关心自己能认识的模板标记语法,
<2>例如 {{}}:{{}} 语法被称之为 mustache 语法,八字胡啊。
var template = require('art-template')
var fs = require('fs')
// var tplStr = `
// <!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8">
// <title>Document</title>
// </head>
// <body>
// <p>大家好,我叫:{{ name }}</p>
// <p>我今年 {{ age }} 岁了</p>
// <h1>我来自 {{ province }}</h1>
// <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
// </body>
// </html>
// `
fs.readFile('./tpl.html', function (err, data) {
if (err) {
return console.log('读取文件失败了')
}
// 默认读取到的 data 是二进制数据
// 而模板引擎的 render 方法需要接收的是字符串
// 所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用
var ret = template.render(data.toString(), {
name: 'Jack',
age: 18,
province: '北京市',
hobbies: [
'写代码',
'唱歌',
'打游戏'
],
title: '个人信息'
})
console.log(ret)
})
node服务端渲染:
- 在 Node 中使用 art-template 模板引擎说白了就是在服务端使用模板引擎
- 模板引擎最早诞生于服务端,后来才发展到了前端
- 模板引起最早就是诞生于服务器领域,后来才发展到了前端。
服务端渲染和客户端渲染的区别:
客户端渲染不利于 SEO 搜索引擎优化
服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
- 所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的而是两者结合来做的
①例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化
②而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染