【铺垫知识】黑马程序员 Vue 学习笔记
文章目录ES6模块化1. 回顾 node.js 中如何实现模块化2. 前端模块化规范的分类3. 什么是 ES6 模块化规范4. ES6模块化的基本语法4.1 默认导出4.2 默认导入4.3 按需导出 和 按需导入Promise1. 回调地狱1.1 Promise的基本概念1.2 then-fs 异步读取文件内容2. 通过 .catch 捕获错误3. Promise.all() 方法4. Promi
ES6模块化
1. 回顾 node.js 中如何实现模块化
node.js 遵循了 CommonJS 的模块化规范。其中:
- 导入其他模块使用 require () 方法
- 模块对外共享成员使用 module.exports 对象
模块化的好处:
大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己
2. 前端模块化规范的分类
在 ES6 模块化规范诞生前,有其他如 AMD 、 CMD 、 CommonJS 模块化规范。但这些都不是官方的,还是存在一定的差异性和局限性
例如:
AMD 和 CMD 适用于浏览器端的 JavaScript 模块化
CommonJS 适用于服务器端的 JavaScript 模块化
为了降低学习难度和开发成本,统一的 ES6 模块化 就诞生了!
3. 什么是 ES6 模块化规范
ES6 模块化规范中定义:
- 每个 JS 文件都是一个独立的模块
- 要导入模块 使用 import 关键字
- 向外共享模块 使用 export 关键字
4. ES6模块化的基本语法
主要包含以下三种用法
- 默认导出和默认导入
- 按需导出和按需导入
- 直接导入并执行模块中的代码
4.1 默认导出
语法:export default 默认导出的成员
let n1 = 10
let n2 = 20
function show () {}
// 向外共享对象
export default {
n1,
show
}
4.2 默认导入
语法:import 接收名称 from ’ 模块标识符 ’
import m1 from './1. 默认导出'
console.log(m1);
只能拿到 n1 和 show
4.3 按需导出 和 按需导入
按需导出 语法:emport 按需导出的成员
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say() { }
按需导入 语法:import {s1} from ’ 模块标识符 ’
import { s1, s2, say } from "./3.按需导出";
Promise
1. 回调地狱
多层回调函数的相互嵌套,就形成了回调地狱。
setTimeout(() => { // 第一层
console.log('延时一秒后输出');
setTimeout(() => { //第二层
console.log('再延时两秒输出');
setTimeout(() => { //第三层
console.log('再延时三秒');
}, 3000)
}, 2000)
}, 1000);
缺点:代码耦合性强,牵一发而动全身,难以维护
为解决这个问题,提出了 Promise 的概念
1.1 Promise的基本概念
① Promise 是一个构造函数
- 我们可以创建 Promise 的实例 const p = new Promise()
- new 出来的 Promise 实例对象,代表一个异步操作
② Promise.prototype 上包含一个 .then() 方法
③ .then() 方法用来预先制定成功和失败的回调函数
- p.then( 成功的回调函数,失败的回调函数 )
- p.then( result => { } , error => { } )
- 成功的回调函数必选,失败的回调函数可选
1.2 then-fs 异步读取文件内容
调用 then-f 提供的 readFile() 方法,可以异步的读取文件的内容,它的返回值是 Promise 的实例对象。
因此可以调用 .then() 方法 为每个 Promise 异步操作制定成功和失败之后的回调函数。
import thenFs from 'then-fs'
// thenFs.readFile('./files/1.txt', 'utf8') 会拿到它的 Promise 对象
thenFs.readFile('./files/1.txt', 'utf8').then((r1) => { console.log(r1) })
thenFs.readFile('./files/2.txt', 'utf8').then((r2) => { console.log(r2) })
thenFs.readFile('./files/3.txt', 'utf8').then((r3) => { console.log(r3) })
// 当前我们只是异步的读取数据,无法保证顺序
- 优化:
import thenFs from 'then-fs'
// thenFs.readFile('./files/1.txt', 'utf8') 会拿到它的 Promise 对象
thenFs.readFile('./files/1.txt', 'utf8')
.then((r1) => {
console.log(r1);
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2);
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3);
})
2. 通过 .catch 捕获错误
在 Promise 的链式操作中 如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理
import thenFs from 'then-fs'
// thenFs.readFile('./files/1.txt', 'utf8') 会拿到它的 Promise 对象
thenFs.readFile('./files/11.txt', 'utf8') // 没有 11.txt文件
.then((r1) => {
console.log(r1);
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2);
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3);
})
.catch((err) => {
console.log(err.message);
})
// 报错: ENOENT: No such file
3. Promise.all() 方法
Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后 才会执行下一步的 .then 操作(等待机制)
import thenFs from "then-fs";
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8')
]
Promise.all(promiseArr).then(result => {
console.log(result);
})
//['111','222','333']
4. Promise.race() 方法
只要任何一个异步操作完成,就立即执行下一步的 .then 操作(赛跑机制)
import thenFs from "then-fs";
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8')
]
Promise.race(promiseArr).then(result => {
console.log(result);
})
// 333
5. 封装读文件的方法
方法封装的要求:
- ① 方法的名称要定义为 getFile
- ② 方法接收一个 形参 fpath ,标识要读取的文件的路径
- ③ 方法的返回值为 Promise 实例对象
5.1 getFile 方法的基本定义
import fs from 'fs'
function getFile(fpath) {
// 如果调用 getFile 函数,就返回一个 Promise 对象
return new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf8', (err, dataStr) => {
// 如果发生错误,就把 err 传进去 reject对象
if (err) return reject(err)
// 如果上一句没有执行 说明成功了 就把 dataStr 传给 resolve
resolve(dataStr)
})
})
}
getFile('./files/1.txt').then((r1) => { console.log(r1) }, (err) => { console.log(err.message); })
async / await
1. 什么是 async / await
async / await 是 ES8 引入的新语法,用来简化 Promise 异步操作。在此之前,开发者只能通过链式 .then() 的方法 处理 Promise 异步操作
2. async / await 基本使用
import thenFs from 'then-fs'
async function getAllFile() {
const r1 = await thenFs.readFile('../files/1.txt', 'utf8');
console.log(r1);
// 111
}
getAllFile();
3. async / await 注意事项
在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行
// 这里 A 是同步执行
console.log('A');
async function getAllFile() {
console.log('B'); // 直到这里都是 同步执行,下面碰到第一个 await,于是退出主线程并进入第 12 行代码,后面的都是异步执行
const r1 = await thenFs.readFile('../files/1.txt', 'utf8');
const r2 = await thenFs.readFile('../files/2.txt', 'utf8');
const r3 = await thenFs.readFile('../files/3.txt', 'utf8');
console.log(r1, r2, r3);
console.log('D');
}
getAllFile();
console.log('C');
宏任务和微任务
1. 什么是宏任务和微任务
JavaScript 把异步任务分为了两类,分别是:
① 宏任务
- 异步 AJAX 请求
- setTimeout、setInterval
- 文件操作
- 其他宏任务
② 微任务
- promise.then, .catch 和 .finally
- process.nextTick
- 其他微任务
2. 宏任务和微任务的执行顺序
宏任务完成 -> 判断有微任务? -> 执行所有微任务 -> 下一个宏任务
API接口案例
1. 案例需求
基于 MySQL 数据库 + Express 对外提供用户列表的API接口服务。用到技术如下:
- 第三方包 express 和mysql2
- ES6 模块化
- Promise
- async / await
2. 主要实现步骤
① 搭建项目的基本结构
② 创建基本的服务器
③ 创建 db 数据库操作模块
④ 创建 user_ctrl 业务模块
⑤ 创建 user_router 路由模块
3. 搭建项目的基本结构
① 启用 ES6 模块化支持
- 在 package.json 中声明 “type”:“module”
② 安装第三方依赖包
- 运行 npm install express@4.17.1 mysql2@2.2.5
4. 创建基本的服务器
import express from 'express'
const app = express()
// 启用服务器,并启动在 80 端口
app.listen(80, () => {
console.log('server running at http://127.0.0.1');
})
5. 创建 db 数据库操作模块
新创建文件夹 db
import mysql from 'mysql2'
// mysql.creatPool() 的返回值 是一个数据库的连接对象
const pool = mysql.createPool({
host: '127.0.0.1', // 指定操作哪台电脑上的数据库
port: 3306, // 指定要连接的数据库的端口号
database: 'my_db_01', // 指定操作哪个数据库
user: 'root', // 登录数据库的账号
password: 'admin123' // 密码
});
// 将 pool 导出,供外界使用
export default pool.promise();
6. 创建 user_ctrl 模块
import db from '../db/index.js'
// 使用 ES6 按需导出语法
export async function getAllUser(req, res) {
const [rows] = await db.query('select id, username, nickname from ev_users')
res.send({
status: 0,
message: '获取用户列表数据成功!',
data: rows,
})
}
getAllUser()
7. 创建 user_router 模块
import express from 'express'
import { getAllUser } from '../2.controller/user_ctrl.js'
// 1. 创建路由对象
const router = new express.Router();
// 3. 挂载一个路由规则
// router.get 监听客户端的 GET 请求
// 只要用户是 GET 请求,并且请求 /user 这个地址,就把这次请求,交给 getAlluser 这个函数处理
router.get('/user', getAllUser)
// 2. 将路由对象共享出去
export default router
// 4. 接下来,回到 app.js 文件中挂载
app.js:
import express from 'express'
import userRouter from './3.router/user_router.js'
const app = express()
// 增:1. 调用 app.use('') 进行挂载
// 如果用户是以 /api 方式进行访问,就指定路由模块 userRouter
app.use('/api', userRouter)
// 启用服务器,并启动在 80 端口
app.listen(80, () => {
console.log('server running at http://127.0.0.1');
})
目标
- 能够知道如何使用 ES6 的模块化语法
- 能够知道如何使用 Promise 解决回调地狱的问题
- 能够知道如何使用 async / await 简化 Promise 的调用
- 能够说出什么是 EventLoop
- 能够说出宏任务和微任务的执行顺序
更多推荐
所有评论(0)