(一)ES6模块化

  ES6模块化规范是浏览器端和服务器端通用的模块化开发规范

  • 每个js文件都是一个独立的模块
  • 导入其他模块成员使用import关键字
  • 向外共享模块成员使用export关键字
  • ES6模块化的基本语法
  • 默认导出和默认导入
// 默认导出
let n1 = 10
let n2 = 20
function show() {}
export default {
    n1,
    show
}
// 默认导入
import request from './默认导出js.js'
console.log(request)
// { n1: 10, show: [Function: show] }
  • 注意事项
  • 每个模块中,只允许使用唯一的一次export default
  • 默认导入的时候接收名称可以是任意名称,只要是合法的成员名称即可
  • 按需导出和按需导入
// 按需导出
export let n1 = 56
export function sing(){}
// 按需导入
import { sing } from './按需导出.js'
console.log(sing)//[Function: sing]
  • 注意事项
  • 每个模块中可以使用多次按需导出
  • 按需导入的成员名称必须和按需导出的成员名称保持一致
  • 按需导入时,可以使用as关键字进行重命名
  • 按需导入和默认导入可以一起使用
  • 直接导入并执行模块化的代码
  • 如果指向单纯地执行某个代码中的模块,并不需要模块中向外共享的成员,此时可以直接导入并执行模块代码

(二)Promise

  • 回调地狱
  • 多层回调函数互相嵌套,就形成了回调地狱
  • Promise基本概念
  • Promise是一个构造函数const p = new Promise(),new出来的Promise实例对象,代表一个异步操作
  • Promise.prototype上包含着一个.then()方法
  • .then()方法用来预先指定成功和失败的回调函数(成功的函数是必选的,失败的回调函数是可选的)p.then(result=>{},error=>{})
  • 基于回调函数按顺序读取文件内容
    • 由于node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持Promise的调用方式。因此,要先安装then-fs这个第三方包,从而支持我们基于Promise的方式读取文件内容
    • 调用then-fs提供的readFile()方法,可以异步地读取文件的内容,它的返回值是Promise实例对象。因此可以调用.then()方法为每个Promise异步操作指定成功和失败之后的回调函数
import thenFs from 'then-fs'
// 下述代码无法保证文件的读取顺序
thenFs.readFile('../files/资源网站.txt','utf8').then(result=>{
    console.log(result)
})
thenFs.readFile('../files/软测复习.txt','utf8').then(result=>{
    console.log(result)
})
  • then方法特性
  • 如果上一个.then()方法返回了一个新的Promise实例对象,则可以通过下一个.then()继续进行处理。通过.then()方法的链式调用,就解决了回调地狱的问题
  • 通过.catch捕获错误
  • 在Promise的链式操作中如果发生了错误,可以使用Promise.prototype.catch方法进行捕获和处理
import thenFs from 'then-fs'
// 下述代码无法保证文件的读取顺序
thenFs.readFile('../files/资源网站1.txt','utf8')
.catch(()=>{
    console.log("粗错啦")
})
.then(result=>{
    console.log(result)//undefined
    return thenFs.readFile('../files/软测复习.txt','utf8')
})
.then(result=>{
    console.log(result)
})
  • Promise.all()方法
  • 该方法会发起并行的Promise异步操作,等所有的异步操作全部结束以后才会执行下一步的.then操作(等待机制)
import thenFs from 'then-fs'
const promiseArr = [
    thenFs.readFile('../files/01.txt','utf8'),
    thenFs.readFile('../files/02.txt','utf8'),
    thenFs.readFile('../files/03.txt','utf8'),
]
Promise.all(promiseArr).then((r1)=>{
    console.log(r1)
})
//[ '我是1', '我是0', '我是0.5' ]
  • Promise.race()方法
  • Promise.race()方法会发起并行的Promise异步操作,只要任何一个异步操作完成,就立即执行下一步的.then操作(赛跑机制)
import thenFs from 'then-fs'
const promiseArr = [
    thenFs.readFile('../files/01.txt','utf8'),
    thenFs.readFile('../files/02.txt','utf8'),
    thenFs.readFile('../files/03.txt','utf8'),
]
Promise.race(promiseArr).then((r1)=>{
    console.log(r1)
})
//[ '我是0']
  • 基于Promise封装读文件的方法
  • 方法的名称要定义为getFile
  • 方法接收一个形参,表示要读取的文件路径
  • 方法的返回值为Promise实例对象
// 基于Promise封装读文件的方法
import thenFs from 'then-fs'
function getFile(fpath) {
    return new Promise(function(resolve,reject){
        thenFs.readFile(fpath,'utf8',(err,dataStr)=>{
            if(err)
                return reject(err)
            resolve(dataStr)
        })
    })
}
getFile('../files/01.txt').then(r1=>{console.log(r1)},r2=>console.log(r2))

(三)async和await

   async和await是ES8引入的新语法,用来简化Promise的异步操作,再次出现之前,开发者只能通过.then()的方式处理Promise异步操作

  • 基本使用
import thenFs from "then-fs"

async function getAllFile(){
    const r1 = await thenFs.readFile('../files/01.txt','utf8');
    const r2 = thenFs.readFile('../files/02.txt','utf8');
    const r3 = await thenFs.readFile('../files/03.txt','utf8');
    console.log(r1)//我是1
    console.log(r2)//Promise { _40: 0, _65: 1, _55: '我是0', _72: null }
}
getAllFile()
  • 注意事项
  • 如果在function中使用了await,则function必须被async所修饰
  • 在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行(先同步再异步)

(四)EventLoop

  • JS是一门单线程的编程语言
  • 同步任务和异步任务
  • 同步任务
  • 又叫做非耗时任务,指的是在主线程上排队的哪些任务
  • 只有前一个任务执行完毕,才能执行后一个任务
  • 异步任务
  • 又叫做耗时任务 ,异步任务由JS委托给宿主环境执行
  • 当异步任务执行完毕后,会通知JS主线程执行异步任务的回调函数
  • 同步任务和异步任务的执行过程
  • 同步任务由JS主线程按照次序执行
  • 异步任务委托给宿主环境执行
  • 已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
  • JS主线程的执行栈被清空后,会读取任务队列中的回调函数,按照次序执行
  • JS主线程不断重读上面的第4步
  • Eventloop的基本概念
    • JS主线程从“任务队列”中读取异步任务的回调函数,放到执行栈中依次执行。这个过程是循环不断地,所以整个的这种运行机制又被称作Eventloop(事件循环)

(五)宏任务和微任务

  • 宏任务和微任务
  • 宏任务
  • 异步AJAX请求
  • setTimeout、setInterval
  • 文件操作
  • 其他宏任务
  • 微任务
  • Promise.then、.catch和finally
  • process.nextTick
  • 其他微任务
  • 宏任务和微任务的执行顺序(交替执行)
  • 每个宏任务执行完毕之后,都会检查是否存在等待执行的微任务,如果有,则执行完所有微任务之后,再执行下一个宏任务

(六)API接口案例

  基于MYSQL数据库+Express对外提供用户列表的API接口

  •  创建db数据库操作模块
import mysql from "mysql2"
const pool = mysql.createPool({
    host: '127.0.0.1',
    port: 3306,
    database: 'my_db',
    user: 'root',
    password: '*******'
})
export default pool.promise()
  • 创建user_ctrl模块
import db from "../db/index.js"
// 使用ES6的按需导出方法,将getAllUsers方法导出出去
export async function getAllUsers(req,res){
    try{
        const[rows] = await db.query('select id, username, nickname from ev_users')
        res.send({
            status: 0,
            message: '获取用户列表数据成功',
            data: rows
        })
    }catch(e){
        res.send({
            status: 1,
            message: '获取用户列表数据失败',
            desc: e.message
        })
    }
}
  • 创建user_router路由模块
import express from "express"
import { getAllUsers } from '../controller/user_ctrl.js'
const router = new express.Router()
router.get('/user', getAllUsers)
export default router
  • 使用postman发起get请求获取数据

     http://127.0.0.1:8000/api/user

(七)总结

  • 熟悉并能够熟练使用ES6的模块化语法
  • 默认导出和默认导入,按需导出和按需导入
  • 使用Promise解决回调地狱的问题
  • promise.then()、promise.catch()
  • 使用async和await简化Promise的调用
  • 方法中使用了await,该方法就需要被async修饰
  • Eventloop的含义
  • 宏任务和微任务的执行顺序
  • 在执行下一个宏任务之前,先检查是否有待执行的微任务