vue前置知识

ES6模块化

在学习Node.js时,我已经知道了Node.js遵循的是CommonJS的模块化规范。

下面来学习ES6模块化。

  • ES6模块化规范浏览器端与服务器端通用的模块化开发规范。它的出现极大地降低了前端开发者的模块化学习成本,开发者不需要再额外学习AMD、CMD或CommonJS等模块化规范

ES6模块化规范中定义

  • 每个JS文件都是一个独立的模块
  • 导入其他模块成员使用import关键字
  • 向外共享模块成员使用export关键字

在Node.js中使用ES6模块化

  • 确保node保本高于14。
  • package.json根节点添加"type":"module"

image-20240715121555978

ES6模块化基本语法

默认导出与默认导入

基础语法

export default 默认导出的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let n1 = 10

let n2 = 20

function show(){

}

//默认导出向外共享
export default {
n1,
show

}

默认导入

语法:import 接收名称 from ‘模块标识符’

1
2
3
4
//在2中导入1
import DefaultInput from './1默认导出.js'

console.log(DefaultInput);

查看控制台如下
image-20240715122312440

1默认导出和默认导入的注意事项

  • 一个模块内,export default只允许使用一次,否则会报错

  • 接收被导入的模块时,名称合法即可,切记不能以数字开头

按需导出和按需导入

语法:export +要导出的内容

1
2
3
4
5
export let s1 = 'aaa';

export let s2 = '123';

export function show(){}

语法:import { } from ‘模块标识符’

1
2
3
4
5
import {s1,s2,show} from './3按需导出.js'

console.log(s1);
console.log(s2);
console.log(show);

image-20240715124243118

按需导出和按需导入的注意事项

  • 可以使用多个按需导出,允许多个export存在
  • 按需导入的成员名称按需导入的成员名称必须一致
  • 按需导入时可以通过关键字as进行重命名
    • image-20240715124526831
  • 按需导入可以和默认导入一起使用,即允许export和export default{}同时存在
    • image-20240715124843445

直接导入并执行模块中的代码

语法: import ‘模块标识符’

image-20240715125219627

控制台输出

image-20240715125233577

Promise

Promise的基本概念

1.Promise是一个构造函数

  • 可以通过**const p = new Promise()**创建Promise实例对象
  • new出来的Promise实例对象代表一个异步操作

2.Promise.propertype(原型对象)中包含.then方法

  • 每次new Promise()构造函数得到的实例对象都可以通过原型链的方式访问到.then方法,例如p.then()

  • .then()方法可以用来预先指定成功和失败的回调函数

    • p.then(成功回调,失败回调)
    • p.then(result=>{},error=>{})
    • 成功回调函数必选,失败回调函数是可选的

基于回调函数按顺序读取文件内容

下面这种无法保证读取文件的顺序。

1
2
3
4
5
import thenFs from "then-fs";
//readFile返回的是Promise的实例对象
thenFs.readFile('./file/1.txt','utf-8').then((r1)=>{console.log(r1);})
thenFs.readFile('./file/2.txt','utf-8').then((r2)=>{console.log(r2);})
thenFs.readFile('./file/3.txt','utf-8').then((r3)=>{console.log(r3);})

Promise支持链式调用,上述代码按顺序读取文件改为如下:由于readFile返回的是Promise的实例对象,所以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import thenFs from "then-fs";

thenFs.readFile('./file/1.txt','utf-8').then((r1)=>{
console.log(r1);
//该函数返回的是promise
return thenFs.readFile('./file/2/txt','utf-8')
})

//因为上述函数的返回值是promise的对象所以可以继续调用.then
.then((r2)=>{
console.log(r2);
return thenFs.readFile('./file/3.txt','utf-8')
})
.then((r3)=>{
console.log(r3);
})

通过.catch方法捕获错误

在可能会出错的位置进行捕获,如果放在最后,那么前面出现问题了会导致后面的无法执行从而直接进入.catch处理错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import thenFs from "then-fs";

thenFs.readFile('./file/1.txt','utf-8').then((r1)=>{
console.log(r1);
//把promise对象返回出去
return thenFs.readFile('./file/2/txt','utf-8')
})
//因为上述函数的返回值是promise的对象所以可以继续调用.then
.then((r2)=>{
console.log(r2);
return thenFs.readFile('./file/3.txt','utf-8')
})
.then((r3)=>{
console.log(r3);
})
//通过.catch捕获错误
.catch(err=>{
console.log(err.message);
})

Promise.all()方法

Promise.all()方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的.then()操作(等待机制)。示例代码如下:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import thenFs from "then-fs";

const promiseAll = [
//该顺序就是最后结果顺序
thenFs.readFile('./file/1.txt','utf-8'),
thenFs.readFile('./file/2.txt','utf-8'),
thenFs.readFile('./file/3.txt','utf-8'),
]

//调用promise.all方法来进行并行操作
Promise.all(promiseAll).then((result)=>{
//成功
console.log(result);
})
// 通过.catch捕获错误
.catch(err=>{
console.log(err.message);
})

image-20240715133453804

Promise.race()方法

Promise.race()方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then 操作(赛跑机制)。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import thenFs from "then-fs";

const promiseAll = [
//该顺序就是最后结果顺序
thenFs.readFile('./file/1.txt','utf-8'),
thenFs.readFile('./file/2.txt','utf-8'),
thenFs.readFile('./file/3.txt','utf-8'),
]

//调用promise.all方法来进行并行操作
Promise.race(promiseAll).then((result)=>{
//成功
console.log(result);
})
// 通过.catch捕获错误
.catch(err=>{
console.log(err.message);
})

可以看出每次执行都会产生不同的结果,这就意味着Promise.race方法是谁先执行完,就继续往下执行,不会等待全部执行完成

image-20240715133705301

案例—基于Promise封装一个异步读取文件的方法

方法的封装要求

  • 方法的名称要定义为 getFile
  • 方法接收一个形参 fpath,表示要读取的文件的路径
  • 方法的返回值为 Promise 实例对象

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
const fs = require('fs')
//定义方法
function getFile(fPath){
//定义功能
// resolve代表成功,reject代表失败
return new Promise(function(resolve,reject){
fs.readFile(fPath,'utf-8',(err,dataStr)=>{
if(err) return reject(err)
resolve(dataStr)
})
})
}

async和await

async/await是ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。在 async/await 出现之前,开发者只能通过链式 .then()的方式处理 Promise 异步操作。

1
2
3
4
5
6
7
8
import thenFs from 'then-fs'

async function getFile(){
const r1 = await thenFs.readFile('./file/1.txt','utf-8')
console.log(r1);
}

getFile();

结果:通过aysnc和await可以直接获取到结果,从而简化了执行过程

image-20240715144857946

注意:

  • 使用了await,那么该方法必须使用async来修饰。
  • 在async方法中,第一个await之前的方法会同步执行,await之后的会异步执行。

EventLoop(事件循环)

同步任务和异步任务

为了防止某个耗时任务导致程序假死的问题,JavaScript 把待执行的任务分为了两类:

同步任务(synchronous)

  • 又叫做非耗时任务,指的是在主线程上排队执行的那些任务
  • 只有前一个任务执行完毕,才能执行后一个任务

异步任务(asynchronous)

  • 又叫做耗时任务,异步任务由JavaScript委托给宿主环境进行执行
  • 当异步任务执行完成后,会通知JavaScript 主线程执行异步任务的回调函数

同步任务和异步任务的执行过程(重点)

一图了解:

image-20240715150154909

EventLoop(事件循环)基本概念

JS有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列的子任务。

下面是一个面试题:

image-20240715150736721

输出顺序是:ADCB

分析:AD是同步任务,会在javascript主线程中执行,CB是耗时任务,异步任务,会放在宿主环境中执行,然而由于延时器是0s所以一但进入宿主环境变会进行执行。

最终顺序是ADCB

异步任务中的宏任务和微任务(重点)

JS中异步任务又分为宏任务和微任务

宏任务

  • 异步的Ajax请求
  • setTimeout、setinterval(该函数作用是设置某个时间,按照一定的时间间隔进行循环执行)
  • 文件操作
  • 其他

微任务

  • Promise.then()、.catch和.fianlly
  • process.nextTick
  • 其他

image-20240715151314118

执行顺序

image-20240715151441537

同步任务:先执行

异步任务:后执行,异步任务中分为了宏任务和微任务。

执行顺序:

先执行宏任务

​ ①如果发现当前宏任务中存在微任务,那么就去执行微任务,执行完微任务之后

​ ②如果当前宏任务中不存在微任务,

执行下一个宏任务。

总结

image-20240715180915356