• nodejs(三)


    规范

    • 每个 js 文件都是一个独立的模块
    • 导入其它模块成员使用 import 关键字
    • 向外共享模块成员使用 export 关键字

    注意:要想使用ES6模块化规范

    必须在 package.json 的根节点中添加 "type": "module" 节点
    在这里插入图片描述

    基本语法

    默认导出 和 默认导入

    语法:

    默认导出的语法: export default 默认导出的成员

    默认导入的语法: import 接收名称 from '模块标识符'

    默认导出

    注意:默认导出只能导出一次

    const money = 1000000
    
    const userName = 'Tricia'
    const age = 22
    const sayHi = () => {
        console.log('hi')
    }
    
    // 注意:默认导出只能导出一次
    export default {
        money,
        userName,
        age,
        sayHi
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    默认导入

    // 导入核心模块
    import fs from 'fs'
    
    console.log(fs)
    
    // 导入自定义模块
    import a from './a.js'
    
    console.log(a.userName)
    a.sayHi()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    按需导入导出

    语法:

    按需导出的语法: export const a = 10

    按需导入的语法: import { a } from '模块标识符'

    按需导出

    注意:

    1. 可以导出多次

    2. 导出的名字是什么,导入的名字必须也一样

    // 按需导出
    // 直接使用export 
    
    // 注意:
    // 1. 可以导出多次
    // 2. 导出的名字是什么,导入的名字必须也一样
    
    export const money = 100000
    export const userName = 'Tricia'
    export const sayHi = () => {
        console.log('hi~~~~~~~')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    按需导入

    导入的一定要加花括号

    如果不想使用导出的名字 as表示重命名

    import { money, userName, sayHi as say } from "./a.js"; // as表示重命名
    
    console.log(userName)
    say()
    console.log(money)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    直接导入

    // 注意: 不需要加from
    import './xxx.js'
    
    • 1
    • 2

    同步异步

    同步(synchronous)

    sync
    按顺序进行

    异步(asynchronous)

    async
    同时进行

    案例

    console.log(1)
    
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 0)
    }, 0)
    
    setTimeout(() => {
        setTimeout(() => {
            console.log(4)
        }, 0)
        console.log(5)
    })
    
    console.log(6)
    
    // 结果:1 6 2 5 3 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Event Loop 事件循环队列

    JavaScript是单线程语言

    单线程执行任务队列的问题:如果前一个任务非常耗时,则后续的任务就不得不一直等待。

    为了防止某个耗时任务导致程序假死的问题,异步代码 由JavaScript 委托给宿主环境(node环境, 浏览器)进行等待执行

    宿主环境

    多线程的

    setTimeout(() => {
        console.log(0)
    }, 0)
    
    console.log(1)
    console.log(2)
    console.log(3)
    console.log(4)
    console.log(5)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    事件循环图解

    异步函数 和 回调函数

    异步函数:

    • setTimeout
    • setInterval
    • ajax
    • fs.readFile

    回调函数:

    1. 把一个函数当成参数传递, 将来特定的时机调用, 这个函数就叫回调函数
    2. 一般什么时候会用到回调函数, 异步的时候 , 定时器, ajax (success, error)
    console.log(1)
    
    setTimeout(function() {
      console.log(2)
      
      setTimeout(function() {
        console.log(4)
      }, 1000)
      
      console.log(5)
    }, 1000)
    
    console.log(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    回调函数缺点:

    1. 阅读性差,回调不会立马执行、
    2. 可维护性差,如果有大量嵌套,会有回调地狱!

    promise

    基本语法

    1. 创建
    const p = new Promise((resolve, reject) => {
     	// promise内部一般可以封装一个异步操作
        // resolve, reject 是 promise 内部提供好给你的两个函数
    	// 成功调用 resolve
    	// 失败调用 reject
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 使用
    p.then(res => { ... }) // 处理成功
     .catch(res => { ... }) // 处理失败
    
    • 1
    • 2

    promise的三个状态

    • pending: 等待 (进行中)
    • fulfilled: 成功 (已完成), 调用了 resolve, promise的状态就会被标记成成功
    • rejected: 失败 (拒绝), 调用了 reject, promise的状态就会被标记成失败

    💡 一旦promise的状态发生变化, 状态就会被凝固(即 不会再改变它的状态)

    promise使用

    // 模拟可以得到的薪资
    
    // resolve函数: 调用resolve promise的状态会发生变化 pending -> fulfilled
    // reject函数:调用reject promise的状态会发生变化 pending -> rejected
    
    // 定义
    const p = new Promise((resolve, reject) => {
        setTimeout(() => {
            // 随机数   
            const money = Math.floor(Math.random() * (20000 - 10000)) + 10000
            console.log(money)
            if (money >= 14000) {
                resolve()
            } else {
                reject()
            }
        }, 3000)
    })
    
    // 调用
    // 如果promise状态是pending 则都不执行
    // 如果是fulfilled,.then()执行
    // 如果是rejected,.catch()执行
    p.then(() => {
        console.log('目标达成')
    }).catch(() => {
        console.log('还要继续努力呀!!')
    })
    
    • 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

    promise链式调用

    如果有多个 promise 需要处理, 支持链式编程。

    如果上一个 .then() 方法中返回了一个新的Promise 实例对象,则可以通过下一个 .then() 继续进行处理。

    因此, .then() 方法是 Promise 支持链式调用的本质原因。

    import fs from 'fs'
    const read = (file) => {
        return new Promise((resolve, reject) => {
            fs.readFile(file, 'utf-8', (err, data) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(data)
                }
    
            })
        })
    }
    
    // 按照顺序读取 a,b,c,d四个文件
    // 不想读c文件,直接删掉就好,便于维护
    read('a.txt')
        .then(data => {
            console.log(data)
            return read('b.txt')
        })
        .then(data => {
            console.log(data)
            return read('c.txt')
        })
        .then(data => {
            console.log(data)
            return read('d.txt')
        })
        .then(data => {
            console.log(data)
        })
        .catch(err => {
            console.log(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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    promise 解决回调地狱

    const p1 = new Promise(function (resolve, reject) {
      // promise 内部会封装一个异步的操作
      // resolve: 成功的时候, 需要调用
      // reject: 失败的时候, 需要调用
      fs.readFile('a.txt', 'utf8', (err, data) => {
        if (err) {
          reject(err)
        } else {
          resolve(data)
        }
      })
    })
    const p2 = new Promise(function (resolve, reject) {
      fs.readFile('b.txt', 'utf8', (err, data) => {
        if (err) {
          reject(err)
        } else {
          resolve(data)
        }
      })
    })
    ...
    ...
    ...
    
    p1.then(res => {
      console.log(res)
      return p2
    }).then(res => {
      console.log(res)
      return p3
    }).then(res => {
      console.log(res)
      return p4
    }).then(res => {
      console.log(res)
    }).catch(err => {
      console.log(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
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    但是这个看起来也不简便,下面进行优化。

    function read (filename) {
      return new Promise(function (resolve, reject) {
        fs.readFile(filename, 'utf8', (err, data) => {
          if (err) {
            reject(err)
          } else {
            resolve(data)
          }
        })
      })
    }
    
    read('a.txt').then(res => {
      console.log(res)
      return read('b.txt')
    }).then(res => {
      console.log(res)
      return read('c.txt')
    }).then(res => {
      console.log(res)
      return read('d.txt')
    }).then(res => {
      console.log(res)
    }).catch(err => {
      console.log(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

    Promise 的常用静态方法

    1. Promise.all([ promise1, promise2, ... ]).then( ... )

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

    2. Promise.race([ promise1, promise2, ... ]).then( .... )

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

      async 和 await

      async 和 await 是一对关键字.必须同时使用

      async

      async用于修饰一个函数, 表示一个函数是异步的.

      如果async函数内没有await, 那么async没有意义的, 全是同步的内容

      只有遇到了await开始往下, 才是异步的开始。

      await

      await 要用在 async 函数中。

      await 后面一般会跟一个promise对象, await会阻塞async函数的执行,直到等到 promise成功的结果(resolve的结果)

      await 只会等待 promise 成功的结果, 如果失败了会报错, 需要 try catch.

      import fs from 'then-fs'
      
      async function read() {
          const data1 = await fs.readFile('a.txt', 'utf-8')
          console.log(data1)
          const data2 = await fs.readFile('b.txt', 'utf-8')
          console.log(data2)
          const data3 = await fs.readFile('c.txt', 'utf-8')
          console.log(data3)
          const data4 = await fs.readFile('d.txt', 'utf-8')
          console.log(data4)
      
      }
      read()
      
      // aaaa  bbbb  cccc   dddd
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      简单的测试一下~

      // await之前的代码是同步的,await之后的代码是异步的
      async function fn() {
          console.log('嘿嘿')
          const res = await fn2()
          console.log(res)
      }
      async function fn2() {
          await 1
          console.log('嘎嘎')
          return 100
      }
      
      fn()
      console.log(222)
      
      // 嘿嘿 222 嘎嘎 100
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      宏任务 微任务

      宏任务:

      主代码块, 定时器, 延时器的代码内容等都属于宏任务, 上一个宏任务执行完, 才会考虑执行下一个宏任务

      微任务:

      当前宏任务执行完,在下一个宏任务开始之前需要执行的任务, promise 的 .then .catch 中的代码都属于微任务

      注意点:

      1. js 主线程遇到异步的内容, 交给浏览器去等待, 不会阻塞主线程
      2. 一定是满足条件后的任务, 才会被添加到任务队列

      简单测试一下~

    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)
    
    // 2 3 6 p2 p1 1  4 5
    
    • 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

    在这里插入图片描述

  • 相关阅读:
    【文档智能】多模态预训练模型及相关数据集汇总
    python制作动态字符画(简单易上手版)
    win11开机动画关闭教程
    驱动器类产品的接口EMC拓扑方案
    odoo17前端js框架的演化
    uni-app父子组件传递数据(更新中)
    CSS特效003:太阳、地球、月球的旋转
    Java面试题-0919
    2023年湖北省电子商务示范企业认定,奖励补贴申报条件解析!
    Bootstrap5 教程
  • 原文地址:https://blog.csdn.net/qq_41675812/article/details/124911750