ES6模块化(官方方案)
配置
- node版本必须大于
v13.0.0
初始化后在 package.json 的根节点中添加
"type": "module"
导出
export default 导出的内容
- 一个模块不能有多个默认导出,最多只能有一个
-
按需
导出
- 可以既有默认导出又有按需导出(不冲突)
- 需要导出那个变量,只需要在前面加上
export
关键字
- 导入
Promise
回调地狱
JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么时候返回结果是不可控的,如果我们希望几个异步请求按照顺序来执行,那么就需要将这些异步操作嵌套起来,嵌套的层数特别多,就会形成 回调地狱 或者叫做 横向金字塔。
语法:
- let p = new Promise( (resolve, reject) => {这里写异步任务})
- 将错误传递给 reject ,将正确结果传递给resolve
- p.then(res => {}, err => {})
- p.then(函数1,函数2)
- 函数1:获取正确的结果
- 函数2:获取错误的结果,(可选)
const fs = require('fs')
// 基础语法
let p = new Promise((resolve, reject) => {
fs.readFile('./文本.txt', 'utf-8', (err, data) => {
// 将错误传递给 reject ,将正确结果传递给resolve
err ? reject(err) : resolve(data.length)
})
})
// then方法获取结果
p.then(
res => { // 函数1获取正确结果
console.log(res)
},
err => { // 函数2获取错误结果
console.log(err)
})
Promise三种状态
- 最初状态:pending,等待中,此时promise的结果为 undefined;
- 当 resolve(value) 调用时,达到最终状态之一:fulfilled,(成功的)完成,此时可以获取结果value
- 当 reject(error) 调用时,达到最终状态之一:rejected,失败,此时可以获取错误信息 error
当达到最终的 fulfilled 或 rejected 时,promise的状态就不会再改变了。
当调用 resolve的时候,Promise 将到达最终的状态。 达到最终状态之后,Promise的状态就不会再改变了。
多次调用 resolve 函数,只有第一次有效,其他的调用都无效。
let p = new Promise((resolve,reject) => {
resolve(123)
resolve(456) //这次调用无效
})
p.then(res => {
console.log(res) //输出123
})
Promise同步异步?
- new Promise()是同步执行的
- 获取结果时(调用 resolve 触发 then方法时)是异步的
console.log(1)
let p = new Promise((resolve,reject) => {
console.log(2)
resolve(3)
console.log(4)
})
console.log(5)
p.then(res => {
console.log(res)
})
console.log(6)
// 输出结果为 1 2 4 5 6 3 只有3变换位置
// 证明只有then方法是异步 new Promise() 里面时同步的
.then方法的链式调用
p.then().then().then
前一个then返回一个Promise对象,Promise对象中resolve值会被下一个then得到
then的链式调用,保证了输出顺序
let P = new Promise((resolve,reject) => {
resolve(100)
})
let P1 = new Promise((resolve,reject) => {
resolve(200)
})
let P2 = new Promise((resolve,reject) => {
resolve(300)
})
P.then(res => {
console.log(res)
return P1
}).then(res => {
console.log(res)
return P2
}).then(res => {
console.log(res)
})
// 输出 100 200 300
// 结论:前一个then返回一个Promise对象,Promise对象中resolve值会被下一个then得到
// 结论:then的链式调用,保证了输出顺序
使用第三方模块读取文件
- npm init - y
- npm i then-fs 安装then-fs模块
- then-fs 将 内置的fs模块封装了,读取文件后,返回 Promise 对象,省去了我们自己封装
- 修改 package.json ,添加 “type”: “module” 表示使用ES6的模块化语法 ```javascript // then-fs 是一个第三方模块 // 它把内置的 then-fs 模块重新封装了一下 // 封装之后,每个方法都返回Promise对象 // 这样的话,咱们就不要new Promise了,直接调用方法,就可以得到Promise对象了 const {readFile} = require(‘then-fs’)
let P = readFile(‘./a.text’,’utf-8’) let p1 = readFile(‘./b.txt’,’utf-8’)
P.then(res => { console.log(res) return p1 }).then(res => { console.log(res) })
---
<a name="MzPsW"></a>
### async和await
代替then语法用来获取结果
<a name="XqgjA"></a>
#### 语法
- `async function fn() {let res = await Promise对象}`
- async 后面必须跟着函数
- await 只能出现在 async的函数内
- await 后面跟着 Promise对象
```javascript
const {readFile} = require('then-fs')
let p1 = readFile('./a.text','utf-8')
let p2 = readFile('./b.txt','utf-8')
async function fn() {
let res1 = await p1
let res2 = await p2
console.log(res1,res2);
}
fn()
async特点
async修饰的函数,总是返回一个Promise对象
await 这个关键字只能出现在 async 的函数内部
- await 需压等待Promise执行完毕,会暂停函数的执行,它下面的所有代码是异步的,会最后执行
错误处理
.catch方法
在 .then 方法的链式调用的末尾加 .catch() 统一处理错误.catch(err => {console.log(err)})
try … catch 语句
使用async和await时,出现错误try会抛出catch会捕捉错误async function fn() {try {}catch(e) {}}
const { readFile } = require('then-fs');
let p1 = readFile('./files/a.txt', 'utf-8');
let p2 = readFile('./files/bbbbb.txt', 'utf-8'); // 故意把这里的路径写错
let p3 = readFile('./files/c.txt', 'utf-8');
// 获取结果,方案一 ------------- 使用then -----------
p1.then(res => {
console.log(res.length)
return p2;
}).then(res => {
console.log(res.length);
return p3;
}).then(res => {
console.log(res.length)
}).catch(err => {
console.log(err);
});
// 获取结果,方案二 --------- 使用async和await -----------
async function abc() {
try {
// try 表示试试,试一试,尝试。这里放正常的代码
let r1 = await p1;
let r2 = await p2; // p2这里出错了,相当于 throw err,抛出错误。并且会终止这段代码执行
let r3 = await p3;
console.log(r1.length, r2.length, r3.length);
} catch (e) {
console.log(e); // e就是上面try里面,抛出的错误
}
}
abc();
宏任务和微任务、事件循环
宏任务
任务(代码) | 宏任务 | 环境 |
---|---|---|
script | 宏任务 | 浏览器 |
事件 | 宏任务 | 浏览器 |
网络请求(Ajax) | 宏任务 | 浏览器 |
setTimeout() 定时器 | 宏任务 | 浏览器 / Node |
fs.readFile() 读取文件 | 宏任务 | Node |
微任务
.thena( () => { **微任务** }) | **await下面的代码**
微任务(microtask)是宏任务中的一个部分,它的执行时机是在同步代码执行之后,下一个宏任务执行之前
事件循环
- 把宏任务循环,循环按以下顺序
- 1.同步任务
- 同步任务先执行,遇到微任务会先跳过
- 2.微任务
- 同步任务执行完毕后,执行微任务
- 3.DOM操作
- 1.同步任务
面试题分析
1
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
resolve(1000)
})
p.then(data => {
console.log(data)
})
console.log(3)
2
console.log(1)
setTimeout(function() {
console.log(2)
new Promise(function(resolve) {
console.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)
})
})
console.log(10)
3
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
console.log(3)
resolve(1000) // 标记为成功
console.log(4)
})
p.then(data => {
console.log(data)
})
console.log(5)
4
new Promise((resolve, reject) => {
resolve(1)
new Promise((resolve, reject) => {
resolve(2)
}).then(data => {
console.log(data)
})
}).then(data => {
console.log(data)
})
console.log(3)
5
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve, reject) => {
console.log(2)
resolve('p1')
new Promise((resolve, reject) => {
console.log(3)
setTimeout(() => {
resolve('setTimeout2')
console.log(4)
}, 0)
resolve('p2')
}).then(data => {
console.log(data)
})
setTimeout(() => {
resolve('setTimeout1')
console.log(5)
}, 0)
}).then(data => {
console.log(data)
})
console.log(6)
6
<script>
console.log(1);
async function fnOne() {
console.log(2);
await fnTwo(); // 右结合先执行右侧的代码, 然后等待
console.log(3);
}
async function fnTwo() {
console.log(4);
}
fnOne();
setTimeout(() => {
console.log(5);
}, 2000);
let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
console.log(6);
resolve();
console.log(7);
})
setTimeout(() => {
console.log(8)
}, 0)
p.then(() => {
console.log(9);
})
console.log(10);
</script>
<script>
console.log(11);
setTimeout(() => {
console.log(12);
let p = new Promise((resolve) => {
resolve(13);
})
p.then(res => {
console.log(res);
})
console.log(15);
}, 0)
console.log(14);
</script>