• 【ES6知识】async 函数与代码优雅写法


    一、async 函数

    1.1 async 函数是什么?

    一句话,它是 Generator 函数的语法糖。ES7 才引入的与异步操作有关的关键字。

    原生JavaScipt案例合集
    JavaScript +DOM基础
    JavaScript 基础到高级
    Canvas游戏开发

    Generator 函数读取两个文件的代码:

    const fs = require('fs');
    
    const readFile = function (fileName) {
      return new Promise(function (resolve, reject) {
        fs.readFile(fileName, function(error, data) {
          if (error) return reject(error);
          resolve(data);
        });
      });
    };
    
    const gen = function* () {
      const f1 = yield readFile('/etc/fstab');
      const f2 = yield readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    上面代码的函数gen可以写成async函数,就是下面这样:

    const asyncReadFile = async function () {
      const f1 = await readFile('/etc/fstab');
      const f2 = await readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

    1.2 基本用法

    async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

    await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。

    async function getStockPriceByName(name) {
      const symbol = await getStockSymbol(name);
      const stockPrice = await getStockPrice(symbol);
      return stockPrice;
    }
    
    getStockPriceByName('goog').then(function (result) {
      console.log(result);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    function testAwait(){
       return new Promise((resolve) => {
           setTimeout(function(){
              console.log("testAwait");
              resolve();
           }, 1000);
       });
    }
     
    async function helloAsync(){
       await testAwait();
       console.log("helloAsync");
     }
    helloAsync();
    // testAwait
    // helloAsync
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    二、代码优雅写法

    2.1 nullish 空值合并运算符 “??”

    空值合并操作符(??)是一个逻辑操作符,当左侧的操作数为null或者undefined时,返回其右侧操作数,否则返回左侧操作数。

    function nullish() {
            // 左侧为 null 或者 undefined 返回 ?? 右侧的值
            let maybeSomething;
    
            // 未优化前
            // if(maybeSomething){
            //   console.log(maybeSomething)
            // } else {
            //   console.log("Nothing found")
            // }
    
            console.log(maybeSomething ?? "Nothing found"); // 'Nothing found'
    
            // 不同于 || ,当左侧为一个假值如 "" 或 0 时,返回 ?? 左侧的值
            maybeSomething = false;
            console.log(maybeSomething ?? 200); // false
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.2 防止崩溃的可选链

    可选链:Optional Chaining Operator 可选链操作符是一个新的js api,它允许读取一个被连接对象的深层次的属性的值而无需明确校验链条上每一个引用的有效性。

    function optChain() {
            const student = {
                name: "Matt",
                age: 27,
                address: {
                    state: "New York"
                },
            };
            // 未优化前
            // console.log(student && student.address && student.address.ZIPCode); 
            // 优化代码
            // console.log(student?.address);//{state: "New York"}
            console.log(student?.address?.ZIPCode);
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    使用可选链可以直接在链式调用的时候进行判断,左侧的对象是否为null或undefined,如果是的,就不再往下运算,而是返回undefined,如果不是,则继续往下运算。

    2.3 解构赋值

    使用解构从数组中拆分值。无需第三方变量完成值的交换,方便又简洁。

    function valReplace() {
            let x = 1;
            let y = 2;
    
    
            // 优化前
            // let temp = x;
            // x = y;
            // y = temp;
    
            // 利用 ES6 解构优化
            [x, y] = [y, x]
            console.log("x:", x, "y:", y); //x: 2 y: 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    function allocated() {
            // 变量应用
            let num1, num2;
            // 传统写法
            num1 = 10;
            num2 = 100;
            // 使用解构语法在一行中分配多个值
            [num1, num2] = [10, 100];
    
            // 对象应用
            let student = {
                name: "Matt",
                age: 29,
            };
            // 传统写法
            let name = student.name;
            let age = student.age;
            // 解构语法赋值
            let {
                name,
                age
            } = student;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.4 将任何值转换为布尔值

    双叹号运算符是将其他类型值转化为布尔值。

    function typeCast() {
            // 使用 Boolean 包装类
            Boolean(0)
            Boolean([])
            Boolean("")
            Boolean({})
    
            // 在 JavaScript 中,你可以使用 !! 在 JS 中将任何内容转换为布尔值
            !!true // true
            !!2 // true
            !![] // true
            !!"Test" // true
            !!false // false
            !!0 // false
            !!"" // false
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.5 数组组合合并

    使用展开运算符可快速实现数组得到展开合并,快速高效。

    function arrConcat() {
            const nums1 = [1, 2, 3];
            const nums2 = [4, 5, 6];
            // concat 方法
            let newArray = nums1.concat(nums2);
            // 使用扩展运算符组合两个数组
            newArray = [...nums1, ...nums2];
    
            // 代替将值推送到数组
            let numbers = [1, 2, 3];
            // push 方法追加内容
            numbers.push(4);
            numbers.push(5);
            // 利用扩展运算符处理
            numbers = [...numbers, 4, 5];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.6 为函数参数提供默认值

    function defaultArgs() {
            // 传统写法
            // function pickUp(fruit) {
            // 	if (fruit === undefined) {
            // 		console.log("I picked up a Banana");
            // 	} else {
            // 		console.log(`I picked up a ${fruit}`);
            // 	}
            // }
    
            // 参数提供默认值写法
            function pickUp(fruit = "Banana") {
                console.log(`I picked up a ${fruit}`)
            }
    
            pickUp("Mango"); // -> I picked up a Mango
            pickUp(); // -> I picked up a Banana
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.7 将对象的值收集到数组中

    function objectVals() {
            const info = {
                name: "Matt",
                country: "Finland",
                age: 35
            };
    
            // 传统写法
            // let data = [];
            // for (let key in info) {
            //   data.push(info[key]);
            // }
    
    
            // 使用Object.values()将对象的所有值收集到一个新数组中
            const data = Object.values(info);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.7 压缩多个条件

    function compCres() {
            const num = 1;
    
            // 传统的通过长 || 检查多个条件链
            // if(num == 1 || num == 2 || num == 3){
            //   console.log("Yay");
            // }
    
            // 使用 includes() 方法压缩条件链
            if ([1, 2, 3].includes(num)) {
                console.log("Yay");
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    指数运算符

    function exponent() {
            // 求幂的传统写法使用 Math.pow()
            Math.pow(4, 2); // 16
            Math.pow(2, 3); // 8
            // ** 指数运算符写法
            4 ** 2 // 16
            2 ** 3 // 8
    
    
            // 向下取整传统写法 Math.floor()
            Math.floor(5.25) // -> 5.0
                // ~~  Math.floor()简写运算符
                ~~5.25 // -> 5.0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三、

    3.1 模块化

    • 后端
    • NodeJs => CommonJS规范
    • 客户端
      • “CommonJS” => AMD规范

      • AMD:Asynchronous Module Definition 异步模块定义

        • define(moduleName,[module],factory); 定义模块
        • require([module],callback); 引入模块
        • RequireJS是对AMD规范的实现
      • CMD规范:阿里贡献模块化

        • Common Module Definition 通用模块定义
        • define(function(require,exports,module){…}) 定义模块(模块主入)

        seajs.use([module路径],function(moduleA,moduleB,moduleC){…}) 使用模块
        与 CommonJS 、AMD规范本质上的不同:CMD规范遵循依赖就近、按需加载,而前两者依赖前置

    ES官方权威 => ES6模块化

    Asynchronous Module Definition 异步模块定义

    import module from ‘模块路径’; 导入模块

    export module; 导出模块

    区别:

    1. commonjs 模块输出的是一个值的拷贝,ES6模块输出的是值得引用
    2. commonjs模块是在运行时加载,es6模块(本身就是模块,只不过浏览器不支持,需要webpack环境编译)是在编译时加载

    3.2 ES6新特性参考

    preview

  • 相关阅读:
    【IO】文件操作基础知识
    cmake学习过程记录
    云端炼丹,算力白嫖,基于云端GPU(Colab)使用So-vits库制作AI特朗普演唱《国际歌》
    【Vue基础】路由以及axios详解与使用案例
    1201. 丑数 III -- 巧用二分搜索
    LeetCode每日一题(双指针)
    C++【继承】
    无人机/飞控--ArduPilot、PX4学习记录(4)
    从零开始学架构笔记
    设计模式 - 迭代器模式
  • 原文地址:https://blog.csdn.net/qq_39335404/article/details/133637531