《ES6-8》基础学习笔记 四

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

学习地址:https://www.bilibili.com/video/BV1v7411G7Ht?p=8

一、async await

1、async await 字面理解

先从字面意思来理解,async 是“异步”的意思,而 await 是等待的意思。所以应该很好理解 async 用于申明一个 异步的function(实际上是async function 对象),而 await 用于等待一个异步任务执行完成的的结果。

并且 await 只能出现在 async 函数中。

2、async、await 如何执行

async 告诉程序这是一个异步操作,await 是一个操作符,即 await 后面是一个表达式。

async 的返回值

 // async
async function testAsync() {
  return "hello async";
}
const data = testAsync();
console.log(data);

如图所示:
在这里插入图片描述

当调用一个 async 函数时,会返回一个 Promise 对象。根据mdn的解释

当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;

当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。async 函数中可能会有 await 表达式,await表达式会使 async 函数暂停执行,直到表达式中的 Promise 解析完成后继续 执行 async中await 后面的代码并返回解决结果。

注意, await 关键字仅仅在 async function中有效

既然返回的是Promise 对象,所以在最外层不能用 await 获取其返回值的情况下,那么肯定可以用原来的方式:then() 链来处理这个 Promise 对象 如

 // async
async function testAsync() {
	return "hello async";
}
let data = testAsync().then( (data) => {
	console.log(data) // hello async                                                 
	return data
});
console.log(data);

如果 async 函数没有返回值,又怎么样呢?很容易想到,它会返回 Promise.resolve(undefined)。

联想一下 Promise 的特点无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。

3、await 操作符

MDN 是这样描述 await 的:

await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行async function。若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。

async 函数返回一个 Promise 对象,当函数执行的时候,
一旦遇到 await 就会先返回,等到触发的异步操作完成,
再接着执行函数体内后面的语句。

按照mdn解释 await会暂停当前async 函数执行,并且await 后面是一个表达式,即这个await 等待的是一个表达式(这个表达式返回promise 对象或者一个具体的值):

● 假如这个表达式如果返回的是一个Promise 对象, 那么它的返回值,实际上就是 Promise 的回调函数 resolve 的参数,如果这个Promise rejected 了,await 表达式会把 Promise 的异常抛出。
● 假如这个表达式如果返回的是一个常量,那么会把这个常量转为Promise.resolve(xx),同理如果没有返回值也是Promise.resolve(underfind)

async function testAwait() {
          const data = await "hello await";
         console.log(data)                                          
        return data
 }

输出 “hello await”

返回promose 对象,成功状态

     function say() {
         return new Promise(function(resolve, reject) {
             setTimeout(function() {
                 let age = 26
                 resolve(`hello, joel。今年我 ${age} 岁`);
             }, 1000);
         });
     }
 
     async function demo() {
        const v = await say(); // 输出:hello, joel。今年我 26 岁  等待这个say 的异步,如果成功把回调 resole 函数的参数作为结果
         console.log(v);
    }
     demo();

返回promise 对象,失败状态

  function say() {
          return new Promise(function(resolve, reject) {
             setTimeout(function() {
                  let age = 26
                 reject(`hello, joel,发生了异常。今年我 ${age} 岁`);
             }, 1000);
         });
     }
      async function demo() {
         try {
             const v = await say(); // 输出:hello, joel,发生了异常。今年我 26 岁  等待这个say 的异步,如果成功把回调 resole 函数的参数作为结果
             console.log(v);
         } catch (e) {
             console.log(e)
         }
     }
     demo();

async/await 相比原来的Promise的优势在于处理 then 链,不必把回调嵌套在then中,只要await 即可,如

  function sing() {
      return new Promise(function(resolve, reject) {
          setTimeout(function() {
              resolve(`来一首好听的歌吧~~~`);
          }, 1000);
      });
  }
  async function demo() {
      try {
         const v = await say(); 
         const s = await sing(); 
         console.log(v); // 输出:hello, joel。今年我 26 岁
         console.log(s) // 来一首好听的歌吧~~~
     } catch (e) {
         console.log(e)
     }
 }
 demo();

如果使用原来的Promise 就是把回调放在then()中。

总结
1、async 告诉程序这是一个异步,awiat 会暂停执行async中的代码,等待await 表达式后面的结果,跳过async 函数,继续执行后面代码

2、async 函数会返回一个Promise 对象,那么当 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值

3、await 操作符用于等待一个Promise 对象,并且返回 Promise 对象的处理结果(成功把resolve 函数参数作为await 表达式的值),如果等待的不是 Promise 对象,则用 Promise.resolve(xx) 转化

二、迭代器(Iterator)

1、ES5实现迭代器

迭代器是一种特殊对象,每一个迭代器对象都有一个next(),该方法返回一个对象,包括value和done属性。

ES5实现迭代器的代码如下:

//实现一个返回迭代器对象的函数,注意该函数不是迭代器,返回结果才叫做迭代器。
function createIterator(items) {
  var i = 0;
  return {
    next() {
      var done = (i >= items.length); // 判断i是否小于遍历的对象长度。
      var value = !done ? items[i++] : undefined; //如果done为false,设置value为当前遍历的值。
      return {
        done,
        value
      }
    }
  }
}
const a = createIterator([1, 2, 3]);

//该方法返回的最终是一个对象,包含value、done属性。
console.log(a.next()); //{value: 1, done: false}
console.log(a.next()); //{value: 2, done: false}
console.log(a.next()); //{value: 3, done: false}
console.log(a.next()); //{value: undefined, done: true}

2、生成器(Generator)

1、生成器是函数:用来返回迭代器。

这个概念有2个关键点,一个是函数、一个是返回迭代器。这个函数不是上面ES5中创建迭代器的函数,而是ES6中特有的,一个带有*(星号)的函数,同时你也需要使用到yield。

//生成器函数,ES6内部实现了迭代器功能,你要做的只是使用yield来迭代输出。
function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator();
console.log(a.next()); //{value: 1, done: false}
console.log(a.next()); //{value: 2, done: false}
console.log(a.next()); //{value: 3, done: false}
console.log(a.next()); //{value: undefined, done: true}

生成器的yield关键字有个神奇的功能,就是当你执行一次next(),那么只会执行一个yield后面的内容,然后语句终止运行。

2、在for循环中使用迭代器

即使你是在for循环中使用yield关键字,也会暂停循环。

   function *createIterator(items) {
      for(let i = 0; i < items.length;  i++) {
        yield items[i]
      }
    }
    const a = createIterator([1, 2, 3]);
    console.log(a.next()); //{value: 1, done: false}

3、yield使用限制

yield只可以在生成器函数内部使用,如果在非生成器函数内部使用,则会报错。

function *createIterator(items) {
    //你应该在这里使用yield
  items.map((value, key) => {
    yield value //语法错误,在map的回调函数里面使用了yield
  })
}
const a = createIterator([1, 2, 3]);
console.log(a.next()); //无输出

4、生成器函数表达式

函数表达式很简单,就是下面这种写法,也叫匿名函数,不用纠结。

const createIterator = function *() {
    yield 1;
    yield 2;
}
const a = createIterator();
console.log(a.next());

5、在对象中添加生成器函数

一个对象长这样:

const obj = {}

我们可以在obj中添加一个生成器,也就是添加一个带星号的方法:

const obj = {
  a: 1,
  *createIterator() {
    yield this.a
  }
}
const a = obj.createIterator();
console.log(a.next());  //{value: 1, done: false}

6、可迭代对象和for of循环

再次默读一遍,迭代器是对象,生成器是返回迭代器的函数。

凡是通过生成器生成的迭代器,都是可以迭代的对象(可迭代对象具有Symbol.iterator属性),也就是可以通过for of将value遍历出来。

function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator();
for(let value of a) {
  console.log(value)
}
// 1 2 3

上面的例子告诉我们生成器函数返回的迭代器是一个可以迭代的对象。其实我们这里要研究的是Symbol.iterator的用法。

function *createIterator() {
  yield 1;
  yield 2;
  yield 3;
}
const a = createIterator(); //a是一个迭代器
const s = a[Symbol.iterator]();//使用Symbol.iterator访问迭代器
console.log(s.next()) //{value: 1, done: false}

Symbol.iterator还可以用来检测一个对象是否可迭代:

typeof obj[Symbol.iterator] === "function"

3、创建可迭代对象

在ES6中,数组、Set、Map、字符串都是可迭代对象。

默认情况下定义的对象(object)是不可迭代的,但是可以通过Symbol.iterator创建迭代器。

const obj = {
  items: []
}
obj.items.push(1);//这样子虽然向数组添加了新元素,但是obj不可迭代
for (let x of obj) {
  console.log(x) // _iterator[Symbol.iterator] is not a function
}//接下来给obj添加一个生成器,使obj成为一个可以迭代的对象。
    const obj = {
      items: [],
      *[Symbol.iterator]() {
        for (let item of this.items) {
          yield item;
        }
      }
    }
    obj.items.push(1)
    //现在可以通过for of迭代obj了。
    for (let x of obj) {
      console.log(x)
    }

1、内建迭代器

上面提到了,数组、Set、Map都是可迭代对象,即它们内部实现了迭代器,并且提供了3种迭代器函数调用。

1、entries() 返回迭代器:返回键值对

    //数组
    const arr = ['a', 'b', 'c'];
    for(let v of arr.entries()) {
      console.log(v)
    }
    // [0, 'a'] [1, 'b'] [2, 'c']
    
    //Set
    const arr = new Set(['a', 'b', 'c']);
    for(let v of arr.entries()) {
      console.log(v)
    }
    // ['a', 'a'] ['b', 'b'] ['c', 'c']//Map
    const arr = new Map();
    arr.set('a', 'a');
    arr.set('b', 'b');
    for(let v of arr.entries()) {
      console.log(v)
    }
    // ['a', 'a'] ['b', 'b']

2、values() 返回迭代器:返回键值对的value

    //数组
    const arr = ['a', 'b', 'c'];
    for(let v of arr.values()) {
      console.log(v)
    }
    //'a' 'b' 'c'//Set
    const arr = new Set(['a', 'b', 'c']);
    for(let v of arr.values()) {
      console.log(v)
    }
    // 'a' 'b' 'c'//Map
    const arr = new Map();
    arr.set('a', 'a');
    arr.set('b', 'b');
    for(let v of arr.values()) {
      console.log(v)
    }
    // 'a' 'b'

3、keys() 返回迭代器:返回键值对的key

   //数组
    const arr = ['a', 'b', 'c'];
    for(let v of arr.keys()) {
      console.log(v)
    }
    // 0 1 2
    
    //Set
    const arr = new Set(['a', 'b', 'c']);
    for(let v of arr.keys()) {
      console.log(v)
    }
    // 'a' 'b' 'c'//Map
    const arr = new Map();
    arr.set('a', 'a');
    arr.set('b', 'b');
    for(let v of arr.keys()) {
      console.log(v)
    }
    // 'a' 'b'

虽然上面列举了3种内建的迭代器方法,但是不同集合的类型还有自己默认的迭代器,在for of中,数组和Set的默认迭代器是values(),Map的默认迭代器是entries()。

2、for of循环解构

对象本身不支持迭代,但是我们可以自己添加一个生成器,返回一个key,value的迭代器,然后使用for of循环解构key和value。

const obj = {
  a: 1,
  b: 2,
  *[Symbol.iterator]() {
    for(let i in obj) {
      yield [i, obj[i]]
    }
  }
}
for(let [key, value] of obj) {
  console.log(key, value)
}
// 'a' 1, 'b' 2

3、字符串迭代器

  const str = 'abc';
    for(let v of str) {
      console.log(v)
    }
    // 'a' 'b' 'c'

4、NodeList迭代器

迭代器真是无处不在啊,dom节点的迭代器你应该已经用过了。

const divs = document.getElementByTagName('div');
for(let d of divs) {
  console.log(d)
}

5、展开运算符和迭代器

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [...a, ...b]
console.log(c) // [1, 2, 3, 4, 5, 6]

6、高级迭代器功能

高级功能不复杂,就是传参、抛出异常、生成器返回语句、委托生成器。

1、传参

生成器里面有2个yield,当执行第一个next()的时候,返回value为1,然后给第二个next()传入参数10,传递的参数会替代掉上一个next()的yield返回值。在下面的例子中就是first。

function *createIterator() {
  let first = yield 1;
  yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next(10)); // {value: 12, done: false}

2、在迭代器中抛出错误

function *createIterator() {
  let first = yield 1;
  yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.throw(new Error('error'))); // error
console.log(i.next()); //不再执行

3、生成器返回语句

生成器中添加return表示退出操作。

function *createIterator() {
  let first = yield 1;
  return;
  yield first + 2;
}
let i = createIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next()); // {value: undefined, done: true}

4、委托生成器

生成器嵌套生成器

function *aIterator() {
  yield 1;
}
function *bIterator() {
  yield 2;
}
function *cIterator() {
  yield *aIterator()
  yield *bIterator()
}

let i = cIterator();
console.log(i.next()); // {value: 1, done: false}
console.log(i.next()); // {value: 2, done: false}

4、异步任务执行器

ES6之前,我们使用异步的操作方式是调用函数并执行回调函数。

书上举的例子挺好的,在nodejs中,有一个读取文件的操作,使用的就是回调函数的方式。

var fs = require("fs");
fs.readFile("xx.json", function(err, contents) {
  //在回调函数中做一些事情
})

任务执行器是一个函数,用来循环执行生成器,因为我们知道生成器需要执行N次next()方法,才能运行完,所以我们需要一个自动任务执行器帮我们做这些事情,这就是任务执行器的作用。

下面我们编写一个异步任务执行器。

//taskDef是一个生成器函数,run是异步任务执行器
function run(taskDef) {
  let task = taskDef(); //调用生成器
  let result = task.next(); //执行生成器的第一个next(),返回result
  function step() {
    if(!result.done) {
    //如果done为false,则继续执行next(),并且循环step,直到done为true退出。
      result = task.next(result.value);
      step();
    }
  }
  step(); //开始执行step()
}

测试一下我们编写的run方法,我们不再需要console.log N个next了,因为run执行器已经帮我们做了循环执行操作:

run(function *() {
  let value = yield 1;
  value = yield value + 20;
  console.log(value) // 21
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值