1.node简介

Node是一个基于Chrome V8引擎的JavaScript代码运行环境。

image-20210205184542161

image-20210205184442760

2.Node运行环境安装

3.快速入门

image-20210205185611403

在控制台 进入当前目录

1
2
3
// 语法 
node ***.js

npm切换源

获取原本镜像地址

1
2
npm get registry 
1

https://registry.npmjs.org/

设为淘宝镜像

1
2
3
npm config set registry http://registry.npm.taobao.org/

yarn config set registry http://registry.npm.taobao.org/

2.global

image-20210206161937758

4.模块化开发

概述

JavaScript在使用时存在两大问题,文件依赖和命名冲突。

image-20210205191355037

开发规范

image-20210205191739447

导出

方式1

image-20210205191913329

方式2

image-20210205192526222

但是

// 当exports 对象 和 moudle.exports 对象指向的不是同一个对象时 以module.exports为准

1
2
3
4
5
6
7
8
9
10
11
12
const greeting = name => `hello ${name}`
const x = 100;

exports.x = x;
module.exports.greeting = greeting;
// 当exports 对象 和 moudle.exports 对象指向的不是同一个对象时 以module.exports为准
module.exports ={
name:'zhangsan'
}
exports = {
age:20
}
1
2
3
const a = require('./04.node.js');
// console.log(a.greeting('zhangsan'));
console.log(a); // {name:'zhangsan'}

导入

image-20210205191932750

案例

1
2
3
// a.js
const add = (n1,n2) => n1 + n2;
exports.add = add // 导出
1
2
3
// b.js
let a = require('./a.js') // 接收 导入时后缀也可以省略
console.log(a.add(3,5));

系统模块

概述

Node运行环境提供的API.因为这些API都是以模块化的方式进行开发的所以我们又称Node运行环境提供的API为系统模块

image-20210205194137711

fs 文件读取操作

image-20210205194611210

image-20210205194645012

1
2
3
4
5
6
7
8
9
10
// 1. 通过模块的名字 fs 对模块进行引用
const fs = require('fs');
// 2. 通过模块内部的 readFile 读取文件内容
fs.readFile('./hellow.js','utf-8',(err,doc)=>{
// 如果文件读取出错 err 是一个对象 包含错误信息
// 如果文件读取正确 err 是 null
// doc是文件读取结果
console.log(err);
console.log(doc);
})

image-20210205195322055

fs 文件写入操作

image-20210205195706312

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 通过模块的名字 fs 对模块进行引用
const fs = require('fs');

// 2. 通过模块内部的 readFile 读取文件内容
fs.readFile('./hellow.js','utf-8',(err,doc)=>{
// 如果文件读取出错 err 是一个对象 包含错误信息
// 如果文件读取正确 err 是 null
// doc是文件读取结果
console.log(err);
console.log(doc);
if(err==null) {
// 如果读取没出错 就调用 写入 api 把文件内容写到 中
fs.writeFile('./05.write.js',doc,(err)=>{
if (err != null) { // 写入出错时调用
console.log('写入出错');
} else { // 写入成功时调用
console.log('写入成功');
}
})
}
})

成功后 看文件中是否有内容

image-20210205200117174

如果 写入文件不存在会自动创建文件 成功

1
fs.writeFile('./err.txt',doc,(err)=>{}

image-20210205200302902

path 路径操作

image-20210205200440586

语法

image-20210205200653900

1
2
3
4
5
// public/uploads/avatar

const path = require('path');
var pat = path.join('publisc','uploads','avatar')
console.log(pat);

image-20210205201121674

相对路径与绝对路径

__dirname是获取绝对路径

image-20210205202037113

1
2
3
4
5
6
7
8
9
10
11
12
const fs = require('fs');
const path = require('path');
console.log(path.join(__dirname))
//C:\Users\LoveCj\Desktop\nodeJS\code\js
console.log(path.join(__dirname, 'hellow.js'));
//C:\Users\LoveCj\Desktop\nodeJS\code\js\hellow.js
// 这里写 绝对路径比较安全
fs.readFile(path.join(__dirname, 'hellow.js'),'utf8',(err,doc) => {
console.log(err);
console.log(doc);

})

第三方模块

1
node init --yes

概述

image-20210205202242041

存在形式

image-20210205202334998

获取第三方模块

npmjs.com

image-20210205202554317

1
2
npm install formidable //安装
npm uninstall formidable

本地安装 全局安装

image-20210205203917050

第三方模块 nodemon

nodemon是一个命令行工具,用以辅助项目开发。
在Node.js中,每次修改文件都要在命令行工具中重新执行该文件,非常繁琐。

  • 使用npm install nodemon -g 下载 -g全局安装
  • 在命令行工具中使用 nodemon命令替代 node命令执行文件

nodemon运行 提示错误:无法加载文件 C:\Users\gxf\AppData\Roaming\npm\nodemon.ps1,因为在此系统上禁止运行脚本。

这是你笔记本禁止运行脚本,解决办法

1.管理员身份打开powerShell

2.输入set-ExecutionPolicy RemoteSigned

img

3 选择Y 或者A ,就好了

第三方模块nrm

nrm ( npm registry manager ): npm下载地址切换工具npm默认的下载地址在国外,国内下载速度慢

image-20210205205600312

  • 使用 npm install nrm -g 下载
  • 查询可用下载地址列表 nrm ls
  • 切换 npm 下载地址 nrm use 下载地址名称

5.Gulp

1.概述

image-20210206081459320

2.初始化

1
2
3
cnpm install gulp

cnpm install gulp-cli -g // 全局安装脚手架

Gulp提供的方法

image-20210206082247339

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
// 引用gulp模块
const gulp = require('gulp');

// 使用 gulp.task 建立任务
// 参数1.任务的名称
// 参数2. 回调函数
gulp.task('frist', () => {
console.log('我们第一个gulp任务执行了');
// 1.获取要处理的文件
gulp.src('./src/css/base.css')
.pipe(gulp.dest('./dist/css'));
});

发现dist 有了 cssimage-20210206083747626

3.Gulp插件

概述

image-20210206083907742

使用

  1. html压缩操作 下载

    1
    npm install gulp-htmlmin

    引用

    1
    const htmlmin = require('gulp-htmlmin');

    调用 压缩html代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // html任务
    // 1. html文件中代码压缩操作
    // 2. 抽取html文件中的公共代码
    gulp.task('htmlmin', () => {
    gulp.src('./src/*.html')
    // 压缩html文件中的代码
    .pipe(htmlmin({collapseWhitespace: true})) // 是否压缩空格
    .pipe(gulp.dest('dist')) // 输出到 dist 下
    })

    image-20210206085112561

  2. 抽离 html 公共代码

    • 第一步 下载插件

      1
      2
      // 下载
      cnpm install gulp-file-include
    • 第二步 引用

      1
      2
      // 调用
      const fileinclude = require('gulp-file-include');
    • 第三步 把html公共样式 抽离出来 写在 common文件夹下

      image-20210206091248371

    • 在html 公共部分文件中写入

      1
      @@include('./common/header.html')
    • 第五步 使用 htmlmin方法

    1
       

    // html任务
    // 1. html文件中代码压缩操作
    // 2. 抽取html文件中的公共代码
    gulp.task(‘htmlmin’, () => {
    gulp.src(‘./src/*.html’)

        .pipe(fileinclude()) // 这一步是 使用公共部分
        // 压缩html文件中的代码
        .pipe(htmlmin({collapseWhitespace: true})) // 是否压缩空格
        .pipe(gulp.dest('dist'))  // 输出到 dist 下
    

    })

    1
    2
    3
    4
    3. css代码操作 less转换以及 css代码压缩

    - 第一步 安装插件

    cnpm install gulp-csso // 压缩 css 的
    cnpm install gulp-less // less 转换为 css

    1
    2
    3

    - 第二步 引用


    const csso = require(‘gulp-csso’);
    const less = require(‘gulp-less’);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    - 第三步 调用

    ```js
    // css 任务
    // 1.将less 转换为 css
    // 2. 将css 代码压缩
    gulp.task('cssmin',()=>{
    // 利用数组的形式选择多个路径 选择 css 路径下 所有的 less 文件以及 css 文件
    gulp.src(['./src/css/*.less','./src/css/*.css'])
    // less 转换为 css
    .pipe(less())
    // css 代码压缩
    .pipe(csso())
    .pipe(gulp.dest('./dist/css'))
    })

  3. js 代码转换es5操作 与 压缩操作

    1
    2
    3
    安装
    cnpm install gulp-babel @babel/core @babel/preset-env 这是转换插件
    cnpm install gulp-uglify 这是压缩插件
    1
    2
    3
    引用
    const babel = require('gulp-babel');
    const uglify = require('gulp-uglify');
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    调用
    // js任务
    // 1.es6 代码转化
    // 2.代码压缩
    gulp.task('jsmin',()=>{
    gulp.src('./src/js/*.js')
    .pipe(babel({
    // 它可以判断当前代码运行环境 将代码转换为当前运行环境所支持的代码
    presets: ['@babel/env']
    })) // uglify压缩
    .pipe(uglify())
    .pipe(gulp.dest('dist/js'))
    })

    进行了转换和压缩

    image-20210206104953190

  4. 构建任务

    1
    2
    // 构建任务
    gulp.task('default', gulp.series(gulp.parallel('htmlmin','cssmin','jsmin','copy')));

4.node_modules文件夹

1.package.json文件

项目描述文件,记录了当前项目信息,例如项目名称、版本、作者、github地址、当前项目依赖了哪些第三方模块等。使用npm init -y命令生成。

使用 npm安装后 package,json会记录你安装过的 依赖

把 node_modules删除后 在文件根目录打开命令行

1
npm install 

就会下载记录的 依赖

image-20210206152034354

image-20210206115802447

别名的用法

1
调用时 输入 npm run bulid 就可以了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"name": "description",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
// 在这里设置 "别名":"命令" 调用时 输入 npm run bulid 就可以了
"test": "echo \"Error: no test specified\" && exit 1",
"build": "nodemon app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"formidable": "^1.2.2",
"gulp": "^4.0.2",
"mime": "^2.5.0"
}
}

2.项目依赖 以及 开发依赖

  • 项目依赖

    1
    2
    开发完成后 用户只想安装项目依赖
    npm install --production

    image-20210206152034354

  • 开发依赖

    1
    npm install --save-dev gulp  安装依赖时设为开发依赖

    image-20210206152442336

  • package-lock.json作用

    image-20210206153441748

5.nodejs中模块的加载机制

案例1

image-20210206155826221

案例2

image-20210206160042456

6.服务器相关

image-20210206162320480

1.Node网站服务器

域名

由于IP地址难于记忆,所以产生了域名的概念,所谓域名就是平时上网所使用的网址。http://www.itheima.com => http://124.165.219.100/
虽然在地址栏中输入的是网址,但是最终还是会将域名转换为ip才能访问到指定的网站服务器。

端口

端口是计算机与外界通讯交流的出口,用来区分服务器电脑中提供的不同的服务。

2.URL

统一资源定位符,又叫URL(Uniform Resource Locator),是专为标识Internet网上资源位置而设的一种编址方式,我们平时所说的网页地址指的即是URL。

url组成

image-20210206163853226

3.开发过程中客户端和服务器端说明

image-20210206164208972

4.创建网站服务器

1
2
3
4
5
6
7
8
9
10
11
12
 // 引用系统模块
const http = require('http');
// 创建web服务器
const app = http.createServer();
// 当客户端发送请求的时候
app.on('request', (req, res) => {
// 响应
res.end('<h1>hi, user</h1>');
});
// 监听3000端口
app.listen(3000);
console.log('服务器已启动,监听3000端口,请访问 localhost:3000')

启动 app.js 在浏览器输入 localhost:3000 就能访问

5.HTTP协议

**超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP**规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端(用户)和服务器端(网站)请求和应答的标准。

image-20210206170102224

6.报文

在HTTP请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式

image-20210206170222996

请求报文

1.请求方式 (Request Method)

  • GET 请求数据
  • POST 发送数据

2.请求地址 (Request URL)

1
2
3
4
5
6
app.on('request', (req, res) => {
req.headers // 获取请求报文
req.url // 获取请求地址
req.method // 获取请求方法
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 用于创建网站服务器的模块
const http = require('http');
// app对象就是网站服务器对象
const app = http.createServer();
// 当客服端有请求来的时候
app.on('request', (req, res) => {
// req请求对象 res响应
// console.log(req);
// 获取请求方式 req.method

// 获取请求地址
// req.url

// 获取请求报文信息
// req.headers
console.log(req.headers);
console.log(req.url);
if (req.url == '/index' || req.url == '/') {
res.end('welcom to homepage')

} else if (req.url == '/list') {
res.end('welcom to list')
} else {
res.end('not found')
}


console.log(req.url);
console.log(req.method);
// if (req.method == 'POST') {
// res.end('post')
// } else if (req.method == 'GET') {
// res.end('GET')
// }



});

app.listen(3000); // 监听端口
console.log('网站服务器启动成功');

响应报文

HTTP状态码

200 请求成功

404 请求的资源没有被找到

500 服务器端错误

400 客户端请求有语法错误

1
2
3
4
5
6
res.writeHead(500) // 设置状态码

res.writeHead(200,{
'content-type':'text/html;charset=utf8' // 默认存文本
})
设置状态码以及返回类型 与 字符编码

内容类型

text/plain 纯文本

text/html

text/css

application/javascript

image/jpeg

application/json

7.请求参数

  • 概述

    image-20210206221608763

  • 分类

    1. GET请求参数

      参数被放置在浏览器地址栏中,例如:http://localhost:3000/`?name=zhangsan&age=20`

      参数获取需要借助系统模块url,url模块用来处理url地址

      node提供了内置模块

      1
      2
      // 用于处理 url 地址
      const httpUrl = require('url');

      使用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      console.log(req.url);
      // 1) req.url 要解析的 url地址
      // 2) true 是否保存为对象 query即为url对象里面的 url解析
      // 利用解构 let query = httpUrl.parse(req.url,true).query
      // let pathname = httpUrl.parse(req.url,true).pathname
      let {query,pathname} = httpUrl.parse(req.url,true);
      console.log(query.name);
      console.log(query.age);

      // 这里进行了修改 利用 pathname 进行判断
      if (pathname == '/index' || pathname == '/') {
      res.end('<h2>welcom to啦啦啦啦 homepage</h2>')

      } else if (pathname == '/list') {
      res.end('welcom to list')
      } else {
      res.end('not found')
      }

      image-20210206223146479

    2. POST请求参数

      image-20210206232328743

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      // 用于创建网站服务器的模块
      const http = require('http');
      // 用于处理 url 地址
      const url = require('url')
      // app对象就是网站服务器对象
      const app = http.createServer();
      // 处理请求参数模块
      const queryString = require('querystring');

      // 当客服端有请求来的时候
      app.on('request', (req, res) => {
      // post 参数是通过事件的方式接收的
      // data 当请求参数传递的时候 触发data事件
      // end 当参数传递完成的时候 触发end事件
      let postParams ='';
      req.on('data',(params)=>{
      postParams += params // 这里之索引进行字符串拼接是因为 请求数据不是一次性发送完毕的
      });

      req.on('end',()=>{

      console.log(queryString.parse(postParams));
      })

      res.end('ok')

      });

      app.listen(3000); // 监听端口
      console.log('网站服务器启动成功');

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      // 导入系统模块querystring 用于将HTTP参数转换为对象格式
      const querystring = require('querystring');
      app.on('request', (req, res) => {
      let postData = '';
      // 监听参数传输事件
      req.on('data', (chunk) => postData += chunk;);
      // 监听参数传输完毕事件
      req.on('end', () => {
      console.log(querystring.parse(postData));
      });
      });

8.路由

http://localhost:3000/index

http://localhost:3000/login

路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么。

image-20210207085247616

1
2
3
4
5
6
7
8
9
10
11
12
13
// 当客户端发来请求的时候
app.on('request', (req, res) => {
// 获取客户端的请求路径
let { pathname } = url.parse(req.url);
if (pathname == '/' || pathname == '/index') {
res.end('欢迎来到首页');
} else if (pathname == '/list') {
res.end('欢迎来到列表页页');
} else {
res.end('抱歉, 您访问的页面出游了');
}
});

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 1.引入系统模块 http
// 2.创建网站服务器
// 3.为网站服务器对象添加请求事件
// 4.实现路由功能
// 1) 获取客户端的请求方式
// 2) 获取客户端的请求地址
const http = require('http');
const url = require('url');
const app = http.createServer();

app.on('request', (req, res) => {
// 获取请求方式
const method = req.method.toLowerCase(); // 转换为小写
// 获取请求地址
const pathname = url.parse(req.url).pathname;
res.writeHead(200,{
'content-type':'text/html;charset=utf-8',
})

if (method === 'get') {
if (pathname === '/' || pathname === '/index') {
res.end('欢迎来到首页')
} else if (pathname === '/list') {
res.end('欢迎来到列表页')

} else {
res.end('您访问的页面不存在')

}
} else if (method === 'post') {

}

})

app.listen(3000)
console.log('服务器启动成功');

9.静态资源

服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS、JavaScript、image文件

1
2
http://www.itcast.cn/images/logo.png

image-20210207092426489

10.动态资源

相同的请求地址不同的响应资源,这种资源就是动态资源。

image-20210207092503457

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 1. 引入系统模块 http
// 2. 创建网站服务器对象
// 3. 为服务器对象添加请求事件
// 4. 实现路由功能
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const app = http.createServer();


app.on('request', (req, res) => {
// 1.用户的请求路径
let pathname = url.parse(req.url).pathname; // 无参数的 获取请求路径
console.log(pathname);
// __dirname 获取文件所在的绝对路径
let lujing = path.join(__dirname,'public',pathname)
// console.log(lujing);
// 读取文件
fs.readFile(lujing,(err,result)=>{
// 如果文件读取失败
if(err != null) {
res.writeHead(404,{
'Content-Type':'text/html;charset=utf-8',
})
res.end('文件读取失败');
return;
}
res.end(result)
})



})

app.listen(3000);
console.log('启动成功');

11.静态资源访问案例

这里引入了一个新模块 mime

1
npm install mime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 1. 引入系统模块 http
// 2. 创建网站服务器对象
// 3. 为服务器对象添加请求事件
// 4. 实现路由功能
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const app = http.createServer();
const mime = require('mime'); //mime有一个 getType方法 能分析文件类型


app.on('request', (req, res) => {
// 1.用户的请求路径
let pathname = url.parse(req.url).pathname; // 无携带参数的 获取请求路径
pathname = pathname == '/'? '/default.html': pathname;

// __dirname 获取文件所在的绝对路径
let lujing = path.join(__dirname,'public',pathname)

// console.log(mime.getType(lujing));
let type = mime.getType(lujing)
// console.log(lujing);
// 读取文件
fs.readFile(lujing,(err,result)=>{
// 如果文件读取失败
if(err != null) {
res.writeHead(404,{
'Content-Type':'text/html;charset=utf-8',
})
res.end('文件读取失败');
return;
}
res.writeHead(200,{
// mime 下的 getType解决文件类型问题
'Content-Type': type
})
res.end(result)
})



})

app.listen(3000);
console.log('启动成功');

12.客户端请求途径

image-20210207105230751

13.同步Api,异步api

1
2
3
4
5
6
7
8
9
// 路径拼接
const public = path.join(__dirname, 'public');
// 请求地址解析
const urlObj = url.parse(req.url);
// 读取文件
fs.readFile('./demo.txt', 'utf8', (err, result) => {
console.log(result);
});

  • 同步API

    同步API:只有当前API执行完成后,才能继续执行下一个API

    1
    2
    3
    console.log('before'); 
    console.log('after');

  • 异步API

    异步API:当前API的执行不会阻塞后续代码的执行

    1
    2
    3
    4
    5
    6
    console.log('before');
    setTimeout(
    () => { console.log('last');
    }, 2000);
    console.log('after');

14.同步Api,异步api的区别

同步API可以从返回值中拿到API执行的结果, 但是异步API是不可以的

1
2
3
4
5
6
  // 同步
function sum (n1, n2) {
return n1 + n2;
}
const result = sum (10, 20);

1
2
3
4
5
6
7
8
9
10
  // 异步
function getMsg () {
setTimeout(function () {
return { msg: 'Hello Node.js' }
}, 2000);
}
const msg = getMsg ();
console.log(msg); // undefined


15.回调函数

自己定义函数让别人去调用。

1
2
3
4
5
// getData函数定义
function getData (callback) {}
// getData函数调用
getData (() => {});

1
2
3
4
5
6
7
8
9
10
11
12
13
// 异步
function getMsg(callback) {
setTimeout(function () {
callback(
{ msg: 'Hello Node.js' }
);

}, 2000);
}
getMsg(function (data) {
console.log(data);
});

16.同步API, 异步API的区别(代码执行顺序)

同步API从上到下依次执行,前面代码会阻塞后面代码的执行

1
2
3
4
5
for (var i = 0; i < 100000; i++) { 
console.log(i);
}
console.log('for循环后面的代码');

异步API不会等待API执行完成后再向下执行代码

1
2
3
4
5
6
7
8
console.log('代码开始执行'); 
setTimeout(() => { console.log('2秒后执行的代码')}, 2000);
setTimeout(() => { console.log('"0秒"后执行的代码')}, 0);
console.log('代码结束执行');
// 代码开始执行
// 代码结束执行
// "0秒"后执行的代码
// 2秒后执行的代码

image-20210207152328883

image-20210207152537867

17.Node.js中的异步API

1
fs.readFile('./demo.txt', (err, result) => {});
1
2
3
var server = http.createServer();
server.on('request', (req, res) => {});

如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题要怎么解决呢?

1
2
fs.readFile('./demo.txt', (err, result) => {});
console.log('文件读取结果');

需求:依次读取A文件、B文件、C文件

回调地狱版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const fs = require('fs');

fs.readFile('./1.txt', 'utf8', (err, data1) => {
console.log(data1);
fs.readFile('./2.txt', 'utf8', (err, data2) => {
console.log(data2);
fs.readFile('./3.txt', 'utf8', (err, data3) => {
console.log(data3);

})
})
})


18.promise

Promise出现的目的是解决Node.js异步编程中回调地狱的问题。

基础语法 实现 异步api执行以及错误的处理 进行了分离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const fs = require('fs');

let promise = new Promise((resolve, reject) => {

fs.readFile('./100.txt', 'utf8', (err, data) => {
if (err != null) {
reject(err)
} else {
resolve(data)
}
})
})

promise.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
})

promise解决回调地狱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const fs = require('fs');

// fs.readFile('./1.txt', 'utf8', (err, data1) => {
// console.log(data1);
// fs.readFile('./2.txt', 'utf8', (err, data2) => {
// console.log(data2);
// fs.readFile('./3.txt', 'utf8', (err, data3) => {
// console.log(data3);

// })
// })
// })
function p1() {
return new Promise((resolve, reject) => {
fs.readFile('./1.txt', 'utf8', (err, data1) => {
resolve(data1)

})
})
}

function p2() {
return new Promise((resolve, reject) => {
fs.readFile('./2.txt', 'utf8', (err, data2) => {
resolve(data2)

})
})
}
function p3() {
return new Promise((resolve, reject) => {
fs.readFile('./3.txt', 'utf8', (err, data3) => {
resolve(data3)

})
})
}


p1().then((r1) => {
console.log(r1);
return p2()
})
.then((r2)=> {
console.log(r2);
return p3()

})
.then((r3) => {
console.log(r3);
})

19.异步函数

异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。

语法

1
2
const fn = async () => {};

1
2
async function fn () {}

async总结

1
2
3
4
5
6
7
1. 普通函数定义前加async关键字 普通函数变成异步函数
2. 异步函数默认返回promise对象
3. 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
4. 在异步函数内部使用throw关键字抛出程序异常
5. 调用异步函数再链式调用then方法获取异步函数执行结果
6. 调用异步函数再链式调用catch方法获取异步函数执行的错误信息

await关键字

1
2
3
4
1. await关键字只能出现在异步函数中
2. await promise await后面只能写promise对象 写其他类型的API是不不可以的
3. await关键字可是暂停异步函数向下执行 直到promise返回结果

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 1. 在普通函数定义的前面加上 async 关键字 普通函数就变成了异步函数
// 2. 异步函数默认返回promise对象
// 3. 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
// 4. 在异步函数内部使用throw关键字抛出程序异常

// await 关键字
// 1.他只能出现在 异步函数 中
// 2. await promise 他可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数

// async function fn() {
// // throw
// throw '发生了一些错误'
// // return 替代 resolve
// return 123


// }

// // console.log(fn());

// fn().then((result) => {
// console.log(result);
// }).catch((err) => {
// console.log(err);
// })

async function p1() {
return 'p1'
}
async function p2() {
return 'p2'
}
async function p3() {
return 'p3'
}

async function run() {
let r1 = await p1();
let r2 = await p2();
let r3 = await p3();
console.log(r1);
console.log(r2);
console.log(r3);

}

run();

20.改造读取文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const fs = require("fs");
//改造现有异步api 使异步api能返回promise对象的方法 从而支持异步函数语法
const promisify = require("util").promisify; // 进行应用 并把promisify 赋值给一个变量
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();