update: CommonJS 规范

This commit is contained in:
qianguyihao 2020-04-14 15:06:43 +08:00
parent d6b0277f05
commit b291152801
5 changed files with 498 additions and 45 deletions

View File

@ -237,12 +237,12 @@ Promise对象, 可以**将异步操作以同步的流程表达出来**。使用
return request2();
})
.then(data => {
// 接口2请求成功后打印接口1的返回结果
// 接口2请求成功后打印接口2的返回结果
console.log(data);
return request3();
})
.then(data => {
// 接口3请求成功后打印接口1的返回结果
// 接口3请求成功后打印接口3的返回结果
console.log(data);
});
</script>

View File

@ -2,39 +2,43 @@
## Node.js的介绍
### 什么是 Node.js(官方解释)
### 什么是 Node.js
Node.js 是一个基于 **Chrome V8** 引擎的 JavaScript 代码运行环境。
Node.js 是一个基于 **Chrome V8** 引擎的 JavaScript 运行环境。Node.js使用了一个**事件驱动**、**非阻塞式I/O**的模型( Node.js的特性使其轻量级又高效。Node.js 的包管理工具 npm 是全球最大的开源库生态系统。
Node.js使用了一个**事件驱动**、**非阻塞式I/O**的模型( Node.js的特性使其轻量级又高效。
Node.js 的包管理器 npm 是全球最大的开源库生态系统。
![](http://img.smyhvae.com/20180301_1540.png)
如上图所示:
- Node 内部采用 Google Chrome 的 V8 引擎,作为 JavaScript 语言解释器;
- Node.js 不是一门语言,也不是 JavaScript 的框架,**Node.js是 JavaScript 语言在服务器端的运行环境(平台)**。
- 通过自行开发的 libuv 库,调用操作系统资源
- Node.js 内部采用 Google Chrome 的 V8 引擎,作为 JavaScript 语言解释器;同时结合自行开发的 libuv 库,扩展了 JS 的功能,使得 JS 既可以在前端进行DOM操作浏览器端又可以在后端调用操作系统资源I/O操作、文件读写、数据库操作等是目前最简单的全栈式语言
### Node.js的特点
- 事件驱动
### 什么是 Node.js非官方解释
- 非阻塞IO模型异步
**Node.js是 JavaScript 语言在服务器端的运行环境(平台)**。Node.js 不是一门语言,也不是 JavaScript 的框架。
- 与PHP、JSP、Python、Perl、Ruby的“既是语言也是平台”不同Node.js的使用JavaScript进行编程运行在 Chrome 的 V8 引擎上。
- 与PHP、JSP等相比PHP、JSP、.net都需要运行在服务器程序上Apache、Naginx、Tomcat、IIS。
Node.js跳过了Apache、Naginx、IIS等HTTP服务器它自己不用建设在任何服务器软件之上。Node.js的许多设计理念与经典架构LAMP = Linux + Apache + MySQL + PHP有着很大的不同可以提供强大的伸缩能力。Node.js没有web容器。
- 轻量和高效
### 运行环境(平台)的含义
- 首先JavaScript 语言通过 Node 在服务器上运行在这个意义上Node 有点像 JavaScript 虚拟机。
首先JavaScript 语言通过 Node 在服务器上运行在这个意义上Node 有点像 JavaScript 虚拟机。
其次Node 生态系统活跃,提供了大量的开源库,使得 JavaScript 语言能与操作系统进行交互比如读写文件、新建子进程在这个层次上Node 又是属于 JavaScript 的工具库。
**引申**
与PHP、JSP、Python、Perl、Ruby的“既是语言也是平台”不同Node.js的使用JavaScript进行编程运行在 Chrome 的 V8 引擎上。
与PHP、JSP等相比PHP、JSP、.net都需要运行在服务器程序上Apache、Naginx、Tomcat、IIS。
Node.js跳过了Apache、Naginx、IIS等HTTP服务器它自己不用建设在任何服务器软件之上。Node.js的许多设计理念与经典架构LAMP = Linux + Apache + MySQL + PHP有着很大的不同可以提供强大的伸缩能力。Node.js没有web容器。
- 其次Node 生态系统活跃,提供了大量的开源库,使得 JavaScript 语言能与操作系统进行交互比如读写文件、新建子进程在这个层次上Node 又是属于 JavaScript 的工具库。
## Node.js和服务器端开发
@ -68,15 +72,15 @@ Node.js 的包管理器 npm 是全球最大的开源库生态系统。
**1、中间层**。
前端访问中间层,中间层再访问后台的 Java/C++ 服务。这样做的好处是:安全性(不会把主服务器暴露在外面)、提高性能(做缓存等)、降低主服务器的复杂度。
前端访问中间层的接口,中间层再访问后台的 Java/C++ 服务。这样做的好处是:安全性(不会把主服务器暴露在外面)、提高性能(做缓存等)、降低主服务器的复杂度。
当然,有时候做 Node.js 开发,是因为:后台人力不够,所以把后台开发的一部分工作量,转移给前端同学。
**2、公司内部工具**。
**2、公司内部工具、项目构建工具**。
**3、小型服务**(比如管理系统)。
**3、小型服务、小型网站的后端**(比如管理系统)。
需要声明的是Node.js很难像 Java/C++ 那样,成为后台的主力开发语言。这并非是因为 Node.js的性能问题实际上Node.js的性能还不错主要是因为Node.js的框架的支持度不够很难独立成为后台开发语言。
需要声明的是:目前来看,Node.js很难像 Java/C++ 那样,成为后台的主力开发语言。这并非是因为 Node.js的性能问题实际上Node.js的性能还不错主要是因为Node.js的框架的支持度不够很难独立成为后台开发语言。
### Node.js 的组成
@ -104,6 +108,8 @@ ECMAScript 是 JS 的语法DOM 和 BOM 浏览器运行环境为 JS 提供的A
### Node 的历史
Node.js 诞生于 2009 年,由 Joyent 的员工 Ryan Dahl 开发而成, 目前官网最新版本已经更新到 13.x.x版本最新稳定的是10.15.3。
- 2008年左右随着 Ajax 的逐渐普及Web 开发逐渐走向复杂化,系统化;
- 2009年2月Ryan Dahl 想要创建一个轻量级,适应现代 Web 开发的平台;
@ -525,7 +531,7 @@ NPM 默认安装到当前正在使用 Node 版本所在目录下。我们建议
![](http://img.smyhvae.com/20180302_1210.png)
### NPM的常用命令
## NPM的常用命令
查看 npm 当前版本:
@ -545,7 +551,8 @@ npm install npm@latest -g
```bash
npm init
npm init --yes 默认配置
# 快速跳过问答式界面,选择默认配置
npm init --yes
```
只在当前工程下安装指定的包:
@ -554,12 +561,125 @@ npm init --yes 默认配置
npm install [package]
```
在全局阿浑惊吓安装指定的包:
在全局安装指定的包:
```
npm install -g [package]
```
安装的包只用于开发环境,不用于生产环境:(会出现在 package.json 文件中的 devDependencies 属性中)
```bash
npm install [package] --save-dev
# 或者
npm install [package] -D
```
安装的包需要发布到生产环境:(会出现在 package.json 文件中的 dependencies 属性中)
```bash
npm install [package] --save
# 或者
npm install [package] -S
```
查看当前目录下已安装的node包
```bash
npm list
```
查看全局已经安装的node包
```bash
npm list -g
```
查看npm帮助命令
```bash
npm --help
```
查看指定命令的帮助:
```bash
npm [指定命令] --help
```
更新指定的包:
```bash
npm update [package]
```
卸载指定的包:
```bash
npm uninstall [package]
```
查看配置信息:
```bash
npm config list
```
查看本地安装的指定包的信息没有则显示empty
```bash
npm ls [package]
```
查看全局安装的指定包的信息没有则显示empty
```bash
npm ls [package] -g
```
查看远程npm上指定包的所有版本信息
```bash
npm info [package]
```
查看当前包的安装路径:
```bash
npm root
```
查看全局包的安装路径:
```bash
npm root -g
```
```bash
```
```bash
```
## 配置 npm 镜像源
由于 npm 默认的下载地址在国外npmjs.com有时候会被墙导致无法下载或者下载很慢。因此我们可以尝试切换成从其他的镜像源下载npm包。
@ -568,9 +688,11 @@ npm install -g [package]
- 方式1临时切换镜像源。
- 方式2通过 NRM 切换镜像源(最为推荐的方式)。
- 方式2切换镜像源
- 方式3cnpm。
- 方式3通过 NRM 切换镜像源(最为推荐的方式)。
- 方式4cnpm。
下面来分别讲一下。
@ -586,8 +708,15 @@ npm install [package] --registry [https://xxx]
npm install express --registry https://registry.npm.taobao.org
```
### 方式2切换镜像源
### 方式2通过 NRM 切换镜像源(推荐)
```bash
npm config set registry https://registry.npm.taobao.org
```
执行上述命令后,以后下载所有 npm 包的时候,都会改为使用淘宝的镜像源。
### 方式3通过 NRM 切换镜像源(推荐)
**NRM**Node Registry Manager。作用是**切换和管理npm包的镜像源**。
@ -624,7 +753,7 @@ nrm use taobao
推荐的国内加速镜像淘宝:<https://npm.taobao.org/>
## 方式3安装cnpm
## 方式4安装cnpm
- 项目地址:<https://npm.taobao.org/>

View File

@ -139,48 +139,195 @@ PS面试时经常会问AMD 和 CMD 的区别。
- 在浏览器端: 模块需要提前编译打包处理。首先,既然同步的,很容易引起阻塞;其次,浏览器不认识`require`语法,因此,需要提前编译打包。
### 模块的暴露和引入
### 暴露模块的方式
Node.js 中只有模块作用域,两个模块之间的变量、方法,默认是互不冲突,互不影响,这样就导致一个问题:模块 A 要怎样使用模块B中的变量&方法呢?这就需要通过 `exports` 关键字来实现。
**方式一**
Node.js中每个模块都有一个 exports 接口对象,我们可以把公共的变量、方法挂载到这个接口对象中,其他的模块才可以使用。
```javascript
module.exports = value
接下来详细讲一讲模块的暴露、模块的引入。
### 暴露模块的方式一: exports
`exports`对象用来导出当前模块的公共方法或属性。别的模块通过 require 函数调用当前模块时,得到的就是当前模块的 exports 对象。
**语法格式**
```js
// 相当于是:给 exports 对象添加属性
exports.xxx = value
```
这个 value 可以是任意的数据类型。
**方式二**
**注意**:暴露的关键词是`exports`,不是`export`。其实,这里的 exports 类似于 ES6 中的 export 的用法,都是用来导出一个指定名字的对象。
```javascript
exports.xxx = value
**代码举例**
```js
const name = 'qianguyihao';
exports.name = name;
```
**问题**: 暴露的模块到底是谁?
### 暴露模块的方式二: module.exports
`module.exports`用来导出一个默认对象,没有指定对象名。
语法格式:
```javascript
// 方式一:导出整个 exports 对象
module.exports = value;
// 方式二:给 exports 对象添加属性
module.exports.xxx = value;
```
这个 value 可以是任意的数据类型。
代码举例:
```js
// 方式1
module.exports = {
name: '我是 module1',
foo(){
console.log(this.name);
}
}
// 我们不能再继续写 module.exports = value2。因为重新赋值会把 exports 对象 之前的赋值覆盖掉。
// 方式2
const age = 28;
module.exports.age = age;
```
`module.exports` 还可以修改模块的原始导出对象。比如当前模块原本导出的是一个对象,我们可以通过 module.exports 修改为导出一个函数。如下:
```js
module.exports = function () {
console.log('hello world')
}
```
### exports 和 module.exports 的区别
最重要的区别:
- 使用exports时只能单个设置属性 `exports.a = a;`
- 使用module.exports时既单个设置属性 `module.exports.a`,也可以整个赋值 `module.exports = obj`
其他要点:
- Node中每个模块的最后都会执行 `return: module.exports`
- Node中每个模块都会把 `module.exports`指向的对象赋值给一个变量 `exports`,也就是说 `exports = module.exports`
- `module.exports = XXX`表示当前模块导出一个单一成员结果就是XXX。
- 如果需要导出多个成员,则必须使用 `exports.add = XXX; exports.foo = XXX`。或者使用 `module.exports.add = XXX; module.export.foo = XXX`
### 问题: 暴露的模块到底是谁?
**答案**:暴露的本质是`exports`对象。【重要】
比如,方式二可以理解成是,**给 exports 对象添加属性**。
比如,方式一的 `exports.a = a` 可以理解成是,**给 exports 对象添加属性**。方式二的 `module.exports = a`可以理解成是给整个 exports 对象赋值。方式二的 `module.exports.c = c`可以理解成是给 exports 对象添加属性。
PS暴露的关键词是`exports`,不是`export`。
Node.js 中每个模块都有一个 module 对象module 对象中的有一个 exports 属性称之为**接口对象**。我们需要把模块之间公共的方法或属性挂载在这个接口对象中,方便其他的模块使用
### 引入模块的方式require
require函数用来在一个模块中引入另外一个模块。传入模块名返回模块导出对象。
### 引入模块的方式
**语法格式**
```
require(xxx)
```js
const module1 = require('模块名');
```
解释:
- 内置模块xxx 为模块名(包名)
- 内置模块:require的是**包名**。
- 下载的第三方模块xxx为模块名包名
- 下载的第三方模块:require的是**包名**
- 自定义模块xxx为模块文件路径。
- 自定义模块require的是**文件路径**。文件路径既可以用绝对路径,也可以用相对路径。后缀名`.js`可以省略。
**代码举例**
```js
const module1 = require('./main.js');
const module2 = require('./main');
const module3 = require('Demo/src/main.js');
```
**require()函数的两个作用**
- 执行导入的模块中的代码。
- 返回导入模块中的接口对象。
### 主模块
主模块是整个程序执行的入口,可以调度其他模块。
```bash
# 运行main.js启动程序。此时main.js就是主模块
$ node main.js
```
### 模块的初始化
一个模块中的 JS 代码仅在模块**第一次被使用时**执行一次,并且在使用的过程中进行初始化,然后会被缓存起来,便于后续继续使用。
代码举例:
1calModule.js:
```js
var a = 1;
function add () {
return ++a;
}
exports.add = add;
```
2main.js在 main.js 中引入 hello.js 模块)
```js
var addModule1 = require('./calModule')
var addModule2 = require('./calModule')
console.log(addModule1.add());
console.log(addModule2.add());
```
在命令行执行 `node main.js` 运行程序,打印结果:
```bash
2
3
```
从打印结果中可以看出,`calModule.js`这个模块虽然被引用了两次,但只初始化了一次。
## CommonJS 在服务器端的实现举例

View File

@ -0,0 +1,171 @@
## CommonJS 规范
CommonJS 规范规定每个模块内部module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即 module.exports是对外的接口对象。加载某个模块其实是加载该模块的 module.exports 对象。
```javascript
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
```
## Node.js 的API文档
Node.js 的API文档 <https://nodejs.org/docs/latest-v8.x/api/index.html>
查阅文档时的常见规律:
- 红色:表示已废弃。
- 绿色表示100%安全使用。
- 黄颜色:表示当前版本可用,其他版本不确定。
## Node.js 中模块的分类
Node.js 应用由模块组成,采用 CommonJS 模块规范。Node.js中的模块分为三种
- 内置模块
- 第三方模块
- 自定义模块
下面简单介绍一下。
### 1、内置模块
```js
const process = require('process');
const path = require('path');
console.log(process.version);
console.log(path.resolve('../'));
```
require方法用于加载模块。
### 2、require 加载第三方包的机制
```js
const express = require('express');
```
require 加载第三方包的机制:
1第三方包安装好后这个包一般会存放在当前项目的 node_modules 文件夹中。我们找到这个包的 package.json 文件并且找到里面的main属性对应的入口模块这个入口模块就是这个包的入口文件。
2如果第三方包中没有找到package.json文件或者package.json文件中没有main属性则默认加载第三方包中的index.js文件。
3如果在 node_modules 文件夹中没有找到这个包或者以上所有情况都没有找到则会向上一级父级目录下查找node_modules文件夹查找规则如上一致。
4如果一直找到该模块的磁盘根路径都没有找到则会报错can not find module xxx。
**3、自定义模块module**
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
举例:
```
var example = require('./example.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
```
今天这篇文章,重点讲一下内置模块中的 **fs 文件处理模块**
## 文件读取
fs 的英文全称是 File System。fs 模块提供了很多api方法我们首先应该学习的方法是**文件读取**。
Node中文件读取的方式主要有以下几种。
### 异步读取文件 fs.readFile()
语法格式:
```js
fs.readFile(file[, options], callback(error, data))
```
代码举例:
```javascript
fs.readFile('c:\\demo\1.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
```
### 同步读取文件 fs.readFileSync()
语法格式:
```js
fs.readFileSync(file[, options])
```
代码举例:
```javascript
try {
const data = fs.readFileSync('c:\\demo\1.txt', 'utf8');
console.log(data);
} catch(e) {
// 文件不存在,或者权限错误
throw e;
}
```
### Node.js 中的异步操作
fs模块对文件的几乎所有操作都有同步和异步两种形式。例如readFile() 和 readFileSync()。
区别:
- 同步调用会阻塞代码的执行,异步则不会。
- 异步调用会将 读取任务 下达到任务队列,直到任务执行完成才会回调。
- 异常处理方面,同步必须使用 try catch 方式,异步可以通过回调函数的第一个参数。【重要】
```javascript
const fs = require('fs');
const path = require('path');
console.time('async');
fs.readFile(path.join('C:\\Users\\qianguyihao\\Downloads', 'H.mp4'), (error, data) => {
if (error) throw error;
// console.log(data);
});
console.timeEnd('async');
console.time('sync');
try {
var data = fs.readFileSync(path.join('C:\\Users\\qianguyihao\\Downloads', 'H.mp4'));
// console.log(data);
} catch (error) {
throw error;
}
console.timeEnd('sync');
```

View File

@ -1,6 +1,12 @@
## JS相关
- JS装饰器
## 性能相关
- 防抖和节流