• es6模块+异步promise+async/await


    ES6模块化

    前端模块化分类

    es6模块化诞生之前,js社区尝试提出了AMD,CMD,Commjs模块化规范

    AMD,CMD适用于浏览器端的JavaScript模块化

    CommonJs适用于服务器端的JavaScript模块化

    Es6即适用于浏览器端也适用于服务器端

    ES6模块化规范中定义

    • 每个js文件都是一个独立的模块
    • 导入其它模块成员使用import
    • 向外共享模块成员使用export
    nodejs默认仅支持CommonJs模块化规范,想基于node.js体验es6的模块化,需要配置
    1:安装了v14.15.1或更高版本的node
    2:在package.json的根节点中添加   "type":"module"  节点
    
    • 1
    • 2
    • 3

    默认导出

    export default 默认导出的成员

    var a = 10;
    function show () {
    
    }
    const arr =[11,22,333]
    export default {
      a,
      show
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:每个模块中,只允许使用唯一的一次export default ,否则会报错!

    默认导入

    注意: 默认导入时接收名称可以任意名称,只要是合法的成员名称就可以

    // 导入export default 向外共享的成员
    import aa from './module/index.js';
    console.log(aa);  //{ a: 10, show: [Function: show] }
    
    • 1
    • 2
    • 3

    按需导入

    import aa,{s1} from './module/index.js'
    
    console.log(s1)
    // 导入export default 向外共享的成员
    // 默认导入时接收名称可以任意名称,只要是合法的成员名称就可以
    // import aa from './module/index.js';
    console.log(aa);  //{ a: 10, show: [Function: show] }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    按需导出

    var a = 10;
    function show () {
      
    }
    const arr = [11, 22, 333]
    
    // 按需导出
    export let s1 = "aaa";
    export function say () { }
    export let s2 = true;
    
    export default {
      a,
      show
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    • 每个模块中可以使用多次按需导出
    • 按需导入的成员名称必须和按需导出的名称保持一致
    • 按需导入时,可以使用as进行重命名
    • 按需导入可以和默认导入一起使用
    import aa,{s1 as a} from './module/index.js'
    
    console.log(a)
    // 导入export default 向外共享的成员
    // 默认导入时接收名称可以任意名称,只要是合法的成员名称就可以
    // import aa from './module/index.js';
    console.log(aa);  //{ a: 10, show: [Function: show] }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    如果只想单纯的执行某个模块中的代码,并不需要得到模块中向外共享的成员

    for (let i = 0; i < 3; i++){
      console.log(i)
    }
    
    • 1
    • 2
    • 3
    import './module/m1.js'
    
    • 1

    promise

    回调地狱

    多层回调函数的相互嵌套,就形成了回调函数

    缺点:

    • 代码难以维护
    • 大量冗余的代码相互嵌套,可读性差
    setTimeout(()=>{
      setTimeout(()=>{
         setTimeout(()=>{
         },1000)
      },2000)
    },1000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如何解决回调地狱

    ES6中新增了Promise的概念

    • Promise是一个构造函数
      • 创建一个promise实例 const p =new Promise()
      • new出来的promise实例对象,代表一个异步操作
    • Promise.prototype上包含一个.then方法
      • 每一次new Promise()构造函数得到的实例对象
      • 都可以通过原型链的方式访问到.then方法
    • .then()方法用来预先指定成功和失败的回调函数
    p.then(成功的回调函数,失败的回调函数)
    p.then(()=>{},()=>{})
    
    • 1
    • 2

    调用.then方法时,成功的回调函数是必选的,失败的回调函数是可选的

    • catch方法 对错误的捕获和处理

    基于then-fs读取文件内容

    由于nodejs官方提供的fs模块仅支持以回调函数的方式读取文件,不支持promise的调用方式

    所以安装then-fs 第三方包,支持基于promise的方式读取文件

    • 下载
      npm install then-fs
    
    • 1
    • 使用

    then-fs提供的readFile方法,可以异步的读取文件内容,它的返回值是Promise的实例对象

    因此可以调用.then()方法为每个promise异步操作指定成功和失败之后的回调函数

    import thenFs from "then-fs";
    // thenFs.readFile('./files/1.txt', 'utf8') 返回promise实例对象
    thenFs.readFile('./files/1.txt', 'utf8')//objf1
      
      .then(d1 => { //成功执行
        console.log(d1,"d1")   //窗前明月光 d1
        return thenFs.readFile('./files/2.txt','utf8')
      })
      //objf1.then(objf2) === objf2
      
      .then(d2 => {
        console.log(d2, "d2");  //hello d2
        return thenFs.readFile('./files/3.txt','utf8')
      })
      //objf2.then(objf3) === objf3
      
      .then(d3 => {
        console.log(d3, "d3");  //13333 d3
        return 8;
      })
      //objf3.then(8) === objf3.then(value = 8)
    
      .then(d4 => {
        console.log(d4, "d4");//8 d4
      })
      .catch(err1 => {  //失败执行
        console.log(err1,0)
      })
    
    • 1
    • 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
    • 27
    • 28

    前一个回调函数的返回值是后一个回调函数的参数

    all()方法

    Promise.all()方法会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作

    import thenFs from "then-fs"
    // 1定义一个数组  存放3个文件的异步操作
    const promiseArr = [
      thenFs.readFile('./files/1.txt', 'utf8'),
      thenFs.readFile('./files/2.txt', 'utf8'),
      thenFs.readFile('./files/3.txt','utf8')
    ]
    // 并行  只要有一个报错就都报错
    // 2将promise的数组,作为Promise.all()的参数
    Promise.all(promiseArr)
      .then(([d1, d2, d3]) => {
          console.log(d1,d2,d3)
      })
      .catch(err => {
        console.log(err)
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    race

    不常用
    Promise.race()方法会发起并行的Promise异步操作,只要任何一个异步操作完成,就立即执行下一步的.then操作

    import thenFs from "then-fs"
    // 1定义一个数组  存放3个文件的异步操作
    const promiseArr = [
      thenFs.readFile('./files/1.txt', 'utf8'),
      thenFs.readFile('./files/2.txt', 'utf8'),
      thenFs.readFile('./files/3.txt','utf8')
    ]
    // 并行  只要有一个报错就都报错
    // 2将promise的数组,作为Promise.race()的参数
    Promise.race(promiseArr)
      .then((result) => {
        // 只要任何一个异步操作完成,就立即执行成功的回调函数
         console.log(result)
      })
      .catch(err => {//捕获promise异步操作的错误
        console.log(err)
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    基于promise封装读文件的方法

    要求:
    1:方法的名称getFile
    2:方法接收一个参数 fpath ,表示要读取文件的路径
    3:方法的返回值为promise实例对象
    
    • 1
    • 2
    • 3
    • 4
    getFile方法的基本定义

    只是创建了一个形式上的异步操作

    // 1:名称为getFile
    // 2:接收参数,要读取文件的路径
    
    function getFile (fpath) {
      // 3方法的返回值为Promise的实例对象
      return  new Promise()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    创建具体的异步操作

    需要在new Promise()构造函数中传递一个function函数,将具体的异步操作定义到function函数内部

    function getFile (fpath) {
      // 3方法的返回值为Promise的实例对象
      return new Promise(function () {
        // 4这是一个具体的读文件的异步操作
         fs.readFile(fpath,'utf8',(err,data)=>{})
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    获取.then的两个实参

    通过.then()指定的成功和失败的回调函数,可以在function的形参中进行接收

    function getFile (fpath) {
      // 3方法的返回值为Promise的实例对象
    
      // 5形参 resolve  调用getFile()方法时  通过.then指定的成功的回调函数
      // 5形参 reject   调用getFile()方法时  通过.then指定的失败的回调函数
      return new Promise(function (resolve,reject) {
        // 4这是一个具体的读文件的异步操作
         fs.readFile(fpath,'utf8',(err,data)=>{})
      })
    }
    
    // 调用getFile()
    // getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    调用resolve和reject回调函数

    Promise异步操作的结果,可以调用resolve或reject回调函数进行处理

    // 1:名称为getFile
    // 2:接收参数,要读取文件的路径
    
    function getFile (fpath) {
      // 3方法的返回值为Promise的实例对象
    
      // 5形参 resolve  调用getFile()方法时  通过.then指定的成功的回调函数
      // 5形参 reject   调用getFile()方法时  通过.then指定的失败的回调函数
      return new Promise(function (resolve,reject) {
        // 4这是一个具体的读文件的异步操作
        fs.readFile(fpath, 'utf8', (err, data) => {
          // 只能有一个状态  要么成功 要么失败
          if (err) return reject(err)  //如果读取失败  调用失败的回调函数
          // 读取成功的数据会随着resolve返回  返回给.then的成功的回调函数的形参
          resolve(data)
         })
      })
    }
    
    // 调用getFile()
    // getFile('./files/1.txt').then(成功的回调函数,失败的回调函数)
    
    getFile('./files/1.txt').then((res) =>{
      console.log(res, "res");
    }, (err) => {
      console.log(err, "err");
    })
    
    • 1
    • 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
    • 27

    关于异步的理解:
    群友:加载页面的时候还能执行其他功能就是异步
    老师:异步都有回调函数,但回调函数不一定是异步

    async/await

    async/await 是ES8引入的新语法,用来简化Promise异步操作,在async/await出现之前,我们只能通过.then的方式处理promise异步操作

    使用

    import thenFs from "then-fs";
    // 按照顺序读取文件
    async function getAllFile () {
      const d1 = await thenFs.readFile('./files/1.txt', 'utf8')
      console.log(d1)
      const d2 = await thenFs.readFile('./files/2.txt', 'utf8')
      console.log(d2)
      const d3 = await thenFs.readFile('./files/3.txt', 'utf8')
      console.log(d3)
    }
    getAllFile ()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果在function中使用了await ,那么function 必须被async修饰

    在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行

    用同步的方式写代码,执行的是异步
    thenFs.readFile()是异步

    import thenFs from "then-fs";
    // 按照顺序读取文件
    async function getAllFile () {
      console.log(123);
      // await  等待后面的异步执行完  再执行下面的代码
      const d1 = await thenFs.readFile('./files/1.txt', 'utf8')
      const d2 = await thenFs.readFile('./files/2.txt', 'utf8')
      const d3 = await thenFs.readFile('./files/3.txt', 'utf8')
      console.log(d1, d2, d3);
      console.log("D");
    }
    
    getAllFile()
    // 123
    // 窗前明月光 hello 13333
    // D
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    比如:
    先请求完接口1,拿接口1返回的数据,去当作接口2的请求参数

    用同步的方式,执行异步操作

    async/await是一种语法糖,和promise一样都是为了解决回调地狱

    async意思是将函数变为异步函数,函数内部必有异步操作
    await的意思是等待,等待后面的异步执行完 再执行下面的代码

  • 相关阅读:
    Grafana+Prometheus 搭建 JuiceFS 可视化监控系统
    PyQt 信号与槽之多窗口数据传递(Python)
    去中心化数字身份(DID)的灵魂绑定
    【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
    音视频学习(十四)——rtsp详解
    jquery和jquery-ui拖动元素(vue2)
    在 HBuilderX 中使用 tailwindcss
    python---设计模式(单例模式和工厂模式)
    Haproxy负载均衡集群
    如何检查Windows 11笔记本电脑电池健康状况
  • 原文地址:https://blog.csdn.net/qq_45025670/article/details/126189148