Vue前置知识
# vue
前置知识
- 能够知道如何使用
ES6
的模块化语法 - 能够知道如何使用
Promise
解决回调地狱的问题 - 能够知道如何使用
async/await
简化Promise
的调用 - 能够说出什么是
EventLoop
- 能够说出宏任务和微任务的执行顺序
# ES6
模块化
Tip
在 ES6
模块化之前,JavaScript 社区已经尝试并提出 AMD、CMD、CommonJS
等模块化规范
但是,这些由社区提供的模块化标准,还是存在一定的差异与局限、并不是所有的浏览器与服务器通用的模块化标准,例如:AMD和CMD
适用于浏览器端,CommonJS
适用于服务器端
因此大一统的 ES6
模块化规范诞生
node.js
可以使用es6
中的模块化 :package.json
中添加type:module
节点默认情况下
node.js
使用的是CommonJS
模块化规范
ES6
模块化中规范定义
- 每个
js
文件都是一个独立的模块 - 导入其它模块成员使用
import
关键字 - 向外共享模块成员使用
export
关键字
基本语法
- 默认导出与默认导入
- 按需导出与按需导入
- 直接导入并执行模块中的代码
# 默认导出导入
语法:export default
默认导出成员
let n1 = 10;
let n2 = 20
function show(){}
export default{
n1,
show
}
2
3
4
5
6
7
注意:默认导出只允许导出一次
语法:inport
接收名称 from
模块标识符
import data from "./demo01.js"
console.log(data);
//{n1:10 , show:[Function:show]}
2
3
# 按需导出导入
导出:export
按需导出的成员
export let dat1 = 10;
export let dat2 = 20;
export function show(){}
2
3
导入:import
{按需导入接收名称} from
“模块化标识符”
import {dat1 as data} from "./URL"
console.log(data);
2
注意
- 按需导入的成员名词必须和按需导出的名词一致
- 按需导入时,可以使用 as 关键字进行重命名
- 按需导入和默认导入可以同时存在,配合使用
# 直接导入并执行
如果只想单纯地执行某个模块中的代码,并不需要得到模块中共享的成员
此时,可以使用直接导入方法
for(let i=0;i<3;i++){
console.log(i);
}
2
3
import "./URL"
// 0 1 2
2
# Promise
多层回调函数的相互嵌套,就形成了回调地狱
setTimeout(()=>{
console.log('1');
setTimeout(()=>{
console.log('2');
setTimeout(()=>{
console.log('3');
},3000)
},2000)
},1000)
2
3
4
5
6
7
8
9
- 代码耦合性强,难以维护
- 大量冗余的代码互相嵌套,代码的可读性差
为了解决回调地狱的问题,ES6
新增了 Promise
的概念
# 基本概念
Promise
是一个构造函数我们可以创建
Promise
的实例const p = new Promise()
new 出来的
Promise
实例对象,代表一个异步操作Promise.prototype
上包含一个.then()
方法每一次得到的实例对象,都可以通过原型链的方式访问到
.then()
方法.then()
方法用来预先指定成功和失败的回调函数p.then(成功的回调函数,失败的回调函数)
p.then(result=>{},error=>{})
1成功的回调函数是必选的,失败回调函数可选
# then-fs
的案例
使用 node.js
中的 fs
文件操作模块 基于回调函数顺序读取文件内容
fs.readFile('./URL','utf-8',(err1,r1)={
if(err1){
return err1.massage
}
console.log(r1);
fs.readFile('./URL','utf-8',(err2,r2)={
if(err2){
return err2.massage
}
console.log(r2);
fs.readFile('./URL','utf-8',(err3,r3)={
if(err3){
return err3.massage
}
console.log(r3);
})
})
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
此时就会产生地狱回调函数的问题
调用 then-fs
提供的 readFile()
方法,可以异步读取文件的内容,它的返回值是 Promise
的实例对象。因此可以调用 .then
方法为每个 Promise
异步操作指定成功和失败之后的回调函数
import thenFs from 'then-fs'
thenFs.readFile('./URL','utf-8').then(r1=>{console.log(r1)},err1=>{return err1.message});
import thenFs from 'then-fs'
thenFs.readFile('./URL','utf-8').then(r2=>{console.log(r2)},err2=>{return err2.message});
import thenFs from 'then-fs'
thenFs.readFile('./URL','utf-8').then(r3=>{console.log(r3)},err3=>{return err3.message});
2
3
4
5
6
但是以上无法保证文件的读取顺序
利用 Promise
链式调用,解决问题
thenFs.readFile('./URL1','utf-8').then((r1)=>{
console.log(r1)
return thenFs.readFile('./URL2','utf-8')
}).then((r2)=>{
console.log(r2)
return thenFs.readFile('./URL3','utf-8')
}).then((r3)=>{
console.log(r3)
}).catch(err=>{
console.log(err.message)
})
2
3
4
5
6
7
8
9
10
11
注意
.catch()
方法会捕获到链式调用之前的产生错误异常,不会继续执行后面的链式代码
如果不想影响到后面的链式代码执行,可以把 .catch()
方法提前
# Promise.All()
Promise.All()
方法会发起并行的 Promise
异步操作,等所有的异步操作全部结束后才会执行下一步的 .then()
操作
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./URL1','UTF-8'),
thenFs.readFile('./URL2','UTF-8'),
thenFs.readFile('./URL3','UTF-8'),
]
Promise.all(promiseArr).then(result=>{
console.log(result)//1 2 3
})
2
3
4
5
6
7
8
9
# Promise.race()
Promise.race()
方法会发起并行的 异步操作,只有有任何一个异步操作完成,就立即执行下一步的 .then()
操作
import thenFs from 'then-fs'
const promiseArr = [
thenFs.readFile('./URL1','UTF-8'),
thenFs.readFile('./URL2','UTF-8'),
thenFs.readFile('./URL3','UTF-8'),
]
Promise.race(promiseArr).then(result=>{
console.log(result)//1or2or3
})
2
3
4
5
6
7
8
9
# 封装自己功能的Promise
import fs from 'fs'
//自定义函数
function getFile(fpath){
return new Promise(function(resolve,reject){
fs.readFile(fpath,'utf-8',(err,dataStr)=>{
if(err){
return reject(err)
}
resolve(dataStr)
})
})
}
2
3
4
5
6
7
8
9
10
11
12
调用
getFile('./URL').then((r1)=>{console.log(r1)},(err)=>{console.log(err)});
注意
在构造 Promise
对象里 function函数的两个形参
在传递的时候第一个形参是 then()
方法的成功回调函数 ,第二个形参是失败回调函数
# async
和 await
async/await
是 ES8
引入的新语法,用来简化 promise
异步操作
import thenFs from ''
async getFile(){
const r1 = await thenFs.readFile('url','utf8');
}
2
3
4
await
被使用的函数必须被async
修饰- 在
async
函数中,第一个await
之前的代码同步执行,之后的代码异步执行
console.log('a')
async function f(){
console.log('b')
const r1 = await thenFs.readFile('url','utf8');
console.log(r1)
console.log('c')
}
f()
console.log('d')
/////out
// a b d {r1} c
2
3
4
5
6
7
8
9
10
11
# EventLoop
JavaScript
是一门单线程执行的编程语言,同一时间只能做一件事情
如果前一个任务非常耗时,则后续的任务不得不一直等待,从而导致程序假死问题
同步任务和异步任务
同步任务:
- 非耗时任务,在主线程上排队执行的任务
- 只有前一个任务执行完毕,才能执行后一个任务
异步任务
- 耗时任务,异步任务由
JavaScript
委托给宿主(V8)进行执行 - 当异步任务执行完成后,会通知
JavaScript
主线程执行异步任务的回调函数
- 同步任务由
js
主线程执行 - 异步任务委托给宿主环境执行
- 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
js
主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行- 主线程不断重复第四步操作
整个运行机制称为 EventLoop
示例
console.log('a');
thenFs.readFile(('url','utf-8').then(s=>{
console.log('B');
}))
setTimeout(()=>{
console.log('C');
},0)
console.log('D');
//out - ADCB
2
3
4
5
6
7
8
9
耗时短的回调和函数先进入任务队列
# 宏任务和微任务
js
把异步任务又做了进一步的划分,异步任务又分为
- 宏任务(
macrotask
)- 异步 Ajax 请求
- setTimeout、setInterval
- 文件操作
- 其它宏任务
- 微任务(
microtask
)Promise.then、.catch和.finally
process.nextTick
- 其它微任务
交替执行(微-宏-微...)
示例
demo 1
setTimeout(function(){
console.log('a');
})
new Promise(function(resolve){
console.log('b');
resolve()
}).then(function(){
console.log('c')
})
console.log('d');
//out - bdca
2
3
4
5
6
7
8
9
10
11
demo 2
console.log('1');
setTimeout(function(){//异步任务
console.log('2')
new Promise(function (resolve){//同步任务
consolo.log('3')
resolve()
}).then(function(){//异步任务-微任务
console.log('4')
})
})
new Promise(function (resolve){//同步任务
console.log('5')
resolve()
}).then(function (){//异步任务-微任务
console.log('6')
})
setTimeout (function(){//异步任务
console.log('7')
new Promise (function (resolve){//同步任务
console.log('8')
resolve()
}).then(function(){//异步任务-微任务
console.log('9')
})
})
//out - 1 5 6 2 3 4 7 8 9
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