一、ES6模块化
1. node.js中的模块化
node.js遵循CommonJS的模块化规范,其中
- 导入其他模块使用require()方法
- 模块对外共享使用module.exports对象
2. ES6模块化规范
2.1 ES6模块化规范中的定义
- 每个js都是一个独立的模块
- 导入其他模块使用 import 关键字
- 向外共享模块使用 export 关键字
2.2 在node.js中使用ES6模块化
node.js仅支持CommonJS模块化规范,要使用ES6的规范需要进行如下配置:
- 确保安装了v14.15.1或更高版本的node.js
- 在package.json的根节点中添加 “type”:“module” 节点(cmd输入 npm init -y可以快速初始化package.json文件)
2.3 ES6模块化的基本语法
- 默认导出与默认导入
- 按需导出与按需导入
- 直接导入并执行模块中的代码
2.3.1 默认导出与导入
默认导出: export default 要导出的内容
默认导入: import xxx from ‘xxxx’
每个模块中,export default仅允许使用一次
let name = "dudu"
let age = 23
function sayHello() {
console.log("hello")
}
// 默认导出
export default {
name,
age,
sayHello
}
//默认导入
import hello from './导出.js'
2.3.2 按需导出与按需导入
按需导出:export 按需导出的成员
按需导入:import { xxxx } from ‘xxxx’
// 按需导出
export function sayHello() {
console.log("hello")
}
export let name = "嘟嘟"
// 按需导入
import {name,sayHello} from './导出.js'
console.log(name)
sayHello()
- 每个模块中可使用多次按需导出
- 按需导入和按需导出时的名称要保持一致
- 按需导入时,可以使用as关键字进行重命名
export let a = 23
import {a as age} from './导出.js'
console.log(age)
- 按需导入可以和默认导入一起使用
import hello,{name,a as age,sayHello} from './导出.js'
2.3.3 直接导入并执行
import 'xxx/xxx'
二、 Promise
1. 回调地狱
回调地狱:多层回调函数的相互嵌套
setTimeout(() => {
console.log("第一次回调")
setTimeout(() => {
console.log("第二次回调")
}, 2000);
setTimeout(() => {
console.log("第三次回调")
}, 3000);
}, 1000);
2. Promise
2.1 Promise的理解
- promise是一个构造函数
- 可以通过new创建一个实例
- new出来的Promise实例对象就代表一个异步操作
- promise的原型对象(prototype)上包含一个 .then() 方法
- .then()方法用来指定成功和失败的回调函数
fun.then(成功的回调,失败的回调)
- Promise用于避免回调地狱
2.2 then-fs异步读取文件
- 安装 then-fs
cnpm install then-fs
- 使用
调用then-fs提供的 readFile() 方法,可异步读取文件内容,它的返回值是Promise实例对象
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt','utf-8')
.then(resolve => {
console.log(resolve)
},err1 => {
console.log(err1.message)
})
thenFs.readFile('./files/2.txt','utf-8')
.then(resolve => {
console.log(resolve)
},err2 => {
console.log(err2.message)
})
thenFs.readFile('./files/3.txt','utf-8')
.then(resolve => {
console.log(resolve)
},err3 => {
console.log(err3.message)
})
- .then()的新特性
上一个 .then() 方法若返回了一个新的Promise实例对象,则可以继续.then()调用
此时可以通过 .catch 捕获错误,catch的位置可以提前(这样前面的错误不会导致后面的then无法执行)
import thenFs from 'then-fs'
thenFs
.readFile('./files/1.txt','utf-8')
.then(resolve => {
console.log(resolve)
return thenFs.readFile('./files/2.txt','utf-8')
})
.then(resolve => {
console.log(resolve)
return thenFs.readFile('./files/3.txt','utf8')
})
.then(resolve => {
console.log(resolve)
})
.catch(err => {
console.log(err.message)
})
2.3 Promise.all()方法
Promise.all([Promise1,Promise2,…]) 方法可以把多个Promise实例包装为一个新的Promise实例
只有需要包装的多个Promise实例状态都为成功,新的Promise状态才为成功(等待机制)
const promiseArr = [
thenFs.readFile('./files/1.txt','utf-8'),
thenFs.readFile('./files/2.txt','utf-8'),
thenFs.readFile('./files/3.txt','utf-8')
]
Promise.all(promiseArr)
.then(result => {
console.log(result) //[ '第一个文件', '第二个文件', '第三个文件' ]
})
2.4 Promise.race()方法
Promise.race([promise1,promise2,…])用法和all()类似,
但是只要其中任何一个异步完成,就会立即执行下一步的.then()操作(赛跑机制)
Promise.race(promiseArr)
.then(res => {
console.log(res) //第一个文件
})
三、 async/await
async/await是ES8引入的新语法,用于简化Promise异步操作
如果某个方法返回的是Promise实例,就可以使用await
async function getAllFile() {
const res1 = await thenFs.readFile('./files/1.txt','utf8')
console.log(res1)
const res3 = await thenFs.readFile('./files/3.txt','utf8')
console.log(res3)
const res2 = await thenFs.readFile('./files/2.txt','utf8')
console.log(res2)
}
getAllFile()
- 如果方法内部使用了await则该方法必须被async修饰
- 在async方法中,第一个await之前的方法会同步执行,await之后的方法会异步执行
四、 EventLoop
JavaScript是一门单线程语言,即同一时间只能做一件事
1. 同步任务和异步任务
- 同步任务
- 非耗时任务,指主线程上排队执行的任务
- 只有前一个同步任务执行完成,才能进行下一个同步任务
- 异步任务
- 耗时任务,指由js委托给宿主环境(js的执行环境,如浏览器、node.js等)进行执行
- 当异步任务执行完成后,会通知JavaScript主线程执行异步任务的回调函数
2. 同步任务和异步任务的执行过程
3. 面试题
// 同步任务
console.log('A')
// 异步任务
thenFs.readFile('./files/1.txt','utf8')
.then(res => {
console.log('B')
})
// 异步任务
setTimeout(() => {
console.log('C')
}, 0);
// 同步任务
console.log('D')
以上代码的输出顺序:A D C B
五、宏任务和微任务
异步任务分为宏任务和微任务
1. 宏任务
- 异步Ajax请求
- setTimeout、setInterval
- 文件操作
- 其他宏任务
2. 微任务
- Promise.then、.catch、.finally
- process.nextTick
- 其它微任务
3. 执行顺序
宏任务和微任务是交替执行的
4. 例题
- 分析一下代码的输出顺序
setTimeout(() => {
console.log('1')
});
new Promise( (resolve) => {
console.log('2')
resolve()
}).then(() => {
console.log('3')
})
console.log('4')
6. 例题
// 同步任务
console.log('1')
// 宏任务
setTimeout(() => {
// 同步任务
console.log('2')
// 同步任务
new Promise((resolve) => {
console.log('3')
resolve()
}).then(() => {
// 异步任务
console.log('4')
})
});
// 同步任务
new Promise((resolve) => {
console.log('5')
resolve()
}).then(() => {
// 微任务
console.log('6')
})
// 宏任务
setTimeout(() => {
// 同步任务
console.log('7')
// 同步任务
new Promise((resolve) => {
console.log('8')
resolve()
}).then(() => {
// 微任务
console.log('9')
})
});
结果:1 5 6 2 3 4 7 8 9