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 ,将正确结果传递给resolveerr ? 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对象```javascriptconst {readFile} = require('then-fs')let p1 = readFile('./a.text','utf-8')let p2 = readFile('./b.txt','utf-8')async function fn() {let res1 = await p1let res2 = await p2console.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>
