【es6】中的Generator
Generator
- 一、Generator 是什么?
- 1.1 与普通函数写法不一样,有两个不同
- 二、Generator 使用
- 2.1 书写方法
- 三、yield语句
- 3.1 yield和return
- 3.2 注意事项
- 3.3 yield*语句
- 3.4 yield*应用
- 四、next方法
- 4.1参数
- 4.2 运行逻辑
- 五、异步解决方案
- 六、Generator相关面试题
- 1. 对Iterator、Generator、Async/Await的理解?
- 2. Generator 是怎么做到中断和恢复?
- 总结
一、Generator 是什么?
Generator 函数是 ES6 提供的一种异步编程解决方案,最大特点交出函数的执行权。
和普通函数不一样的是必须调用next()才会执行函数。
1.1 与普通函数写法不一样,有两个不同
- function与函数名之间有个(*)号;
不同于普通函数,可暂停执行,所以加*
区别。 - Generator 函数体内部使用yield语句,可以定义不同的内部状态,其实就是数据不同。
函数内部的状态,就是函数内部的值,它在不同的时候是不一样的。
本质上整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。
yield的命令是异步不同阶段的分界线,有时把yield的当成return。
二、Generator 使用
2.1 书写方法
- 函数名和方法中间有个
*
号,但没规定放置的位置,一般跟在function后面;
- 调用Generator 函数,函数并不执行,返回的是一个指向内部状态指针的对象(遍历器对象)
function* test(){let n = 1;yield n;yield++n;yield--n;return n;
}let t = test();
console.log(t); //test {<suspended>}
返回的是一个对象,并且有next, return,throw方法
- 想打印值,必须调用next方法,使指针下一个状态。也就是每次调用都从上一个指针状态(yield)开始,遇到下一个yield或return语句为止。也就是一段段段执行,yield暂停,next继续执行。
下面调用6次,一个yield一个状态。返回一个对象,value代表值,done代表是否遍历结束(true结束,false未结束)
done为true已经代表函数结束,再打印几次值都为undefined
console.log(t.next()); //{value: 1, done: false}
console.log(t.next()); //{value: 2, done: false}
console.log(t.next()); //{value: 1, done: false}
console.log(t.next()); //{value: 1, done: true}
console.log(t.next()); //{value: undefined, done: true}
console.log(t.next()); //{value: undefined, done: true}
三、yield语句
yield语句就是暂停标志。
3.1 yield和return
相同点:
- 都能返回后面表达式的值。
不同点:
- yield的函数暂停执行时,下一次会从该位置继续向后执行,并且一个函数可有多个yield语句。
- return返回就相当于结束函数,一个函数只有一个return。
3.2 注意事项
- yield后面n+1不会执行,只有调用next方法才会执行。
function* test() {let n = 1;yield n + 1;console.log(n);
}
test(); //此时打印是空白的//必须调用next方法才会执行
console.log(test().next()); //{value: 2, done: false}
2.可以不用yield,但是必须调用next方法才会执行
function* test() {let n = 1;console.log(n);
}
let t = test();
console.log(t.next());
- yield语句不能用在普通函数中。
function test() {yield 1;
}
console.log(test()); // Unexpected number
3.3 yield*语句
Generator 函数内部调用另一个Generator 函数,默认情况无效。
function* A(){yield 1;yield 2;
}
function* B(){yield 3;A();yield 4;
}
for(let i of B()){console.log(i)
}
//3
//4
虽然在B函数中调用了A(),但只能打印出3,4。如果想要调用,就要在前面使用yield*语句。
function* A(){yield 1;yield 2;
}
function* B(){yield 3;yield* A();yield 4;
}
for(let i of B()){console.log(i)
}
//3
//1
//2
//4
yield*是for…of…的一种简写形式,我们知道for…of…可以遍历出具有iterator接口的数据结构(数组,类数组对象,字符串,nodelist等)
3.4 yield*应用
- 数组扁平化
let a = [1,[1,2],[1,2,3]]
function* iterTree(arr){if(Array.isArray(arr)){for(let i = 0;i<arr.length;i++){yield* iterTree(arr[i]);}}else{yield arr;}
}
for(let i of iterTree(a)){console.log(i)
}
- 遍历完全二叉树
// 构建树
function Tree(left,middle,right){this.left = left;this.middle = middle;this.right = right;
}
// 中序遍历函数
function* inorder(t){if(t){yield* inorder(t.left);yield t.middle;yield* inorder(t.right);}
}
// 生成二叉树
function make(array){if(array.length == 1) return new Tree(null,array[0],null);return new Tree(make(array[0]),array[1],make(array[2]));
}
let tree = make([[['a'],'b',['c']],'d',[['e'],'f',['g']]]);
// 遍历二叉树
var result = [];
for(let node of inorder(tree)){result.push(node);
}
console.log(result) //['a', 'b', 'c', 'd', 'e', 'f', 'g']
四、next方法
next方法是使指针指向下一个状态。除了for…of遍历出来,必须调用next才能打印出yield值。
4.1参数
yield语句本身没有返回值,或者总返回undefined。next方法可以带一个参数,这个参数会被当上一个yield语句的返回值。
function* test(x) {var a = yield x-1;var b = yield (a+2);return a+b;
}
let t = test(4);
console.log(t.next()) //{value: 3, done: false}
console.log(t.next(10)) //{value: 12, done: false}
console.log(t.next(4)) //{value: 14, done: true}
第一步:传个4进去,x-1=3,打印出来为3
第二步:传个10进去,这个参数会被当上一个yield语句的返回值,也就是a的值为10,a+2,打印出来为12。
第三步:传个4进去,上一个参数b的值为4,a的值为之前的10,a+b为14。
4.2 运行逻辑
- 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
- 下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。 - 如果该函数没有return语句,则返回的对象的value属性值为undefined
五、异步解决方案
我们之前知道有以下几种异步解决方案:
- 回调函数
所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数。
fs.readFile('/etc/fstab', function (err, data) {if (err) throw err;fs.readFile('/etc/shells', function (err, data) {if (err) throw err;console.log(data);});
});
readFile函数的第三个参数,就是回调函数,等到操作系统返回了/etc/fstab这个文件以后,回调函数才会执行。
- Promise 对象
Promise就是为了解决回调地狱而产生的,将回调函数的嵌套,改成链式调用。
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);});});
};readFile('/etc/fstab').then(data =>{console.log(data)return readFile('/etc/shells')
}).then(data => {console.log(data)
})
- async/await
const asyncReadFile = async function () {const f1 = await readFile('/etc/fstab');const f2 = await readFile('/etc/shells');console.log(f1.toString());console.log(f2.toString());
};
- generator 函数
yield表达式可以暂停函数执行,next方法用于恢复函数执行,这使得Generator函数非常适合将异步任务同步化。
const gen = function* () {const f1 = yield readFile('/etc/fstab');const f2 = yield readFile('/etc/shells');console.log(f1.toString());console.log(f2.toString());
};
区别:
通过上述代码进行分析,将promise、Generator、async/await进行比较:
-
promise和async/await是专门用于处理异步操作的
-
Generator并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署Interator接口…)
-
promise编写代码相比Generator、async更为复杂化,且可读性也稍差
-
Generator、async需要与promise对象搭配处理异步情况
-
async实质是Generator的语法糖,相当于会自动执行Generator函数
-
async使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案
六、Generator相关面试题
1. 对Iterator、Generator、Async/Await的理解?
- 1. Iterator
Iterator 是一个循环接口,任何实现了此接口的数据都可以被 for of 循环遍历;
我们常用的 for…of 循环,都是通过调用被循环对象的一个特殊函数 Iterator 来实现的,但是以前这个函数是隐藏的我们无法访问,从 Symbol 引入之后,我们就可以通过 Symbol.iterator 来直接读写这个特殊函数。
循环语句来说,他并不关心被循环的对象到底是什么,他只负责调用 data[Symbol.iterator] 函数,然后根据返回值来进行循环。
let obj = {}
obj[Symbol.iterator] = function() {let index = 1;return {next() {return {done: index > 5,value: index++}}}
}
for (var i of obj) {console.log(i,obj);
}
- 2. Generator
Generator 可以看做是一个更加灵活的 Iterator ,他们之间是可以互相替代的,但是, Generator 由于可以通过 yield 随时暂停,因此可以很方便进行流程控制和状态管理,而 Iterator 就可能需要你写更多的代码进行相同的操作。
- 3. Async/Await
async是Generator 的一个语法糖;- async 对应的是 *
- await 对应的是 yield
async function count () {let a = await 1;let b = await 2;return a+b
}
2. Generator 是怎么做到中断和恢复?
通过使用 yield 表达式来实现中断和恢复执行的功能。
当 Generator 函数被调用时,它并不会立即执行,而是返回一个迭代器对象。每次调用迭代器对象的 next() 方法时,Generator 函数会从上一次执行的位置继续执行,直到遇到下一个 yield 表达式或函数结束。此时,Generator 函数将返回一个包含当前值和执行状态的对象,其中 value 属性表示 yield 表达式的结果,done 属性表示是否执行完毕。
总结
Generator 函数是一种异步编程解决,可以更好的控制函数执行。其中yield是同步的,调用next()才能打印出值。
函数返回的是一个对象,而next方法返回的也是一个对象,其中有value(值),done(是否遍历完)。
一个next对应一个yield语句,当最后done为true时,再调用next方法,值都是undefined。全部遍历可使用for…of,其原理还是数据结构内部有iterator接口。
相关文章:

【es6】中的Generator
Generator 一、Generator 是什么?1.1 与普通函数写法不一样,有两个不同 二、Generator 使用2.1 书写方法 三、yield语句3.1 yield和return3.2 注意事项3.3 yield*语句3.4 yield*应用 四、next方法4.1参数4.2 运行逻辑 五、异步解决方案六、Generator相关…...

桥梁安全监测方法和内容是什么?
桥梁安全监测方法和内容是什么?桥梁监测是保障桥梁安全和稳定的重要手段。随着科技的进步,桥梁监测技术和设备不断完善,监测内容也越来越全面。本文万宾科技小编将为大家介绍桥梁安全监测的方法和内容,以期帮助大家更好地了解这一领域。 桥梁…...

prometheus部署及钉钉告警集成Grafana
1、准备工作 安装包 📎alertmanager-0.23.0.linux-amd64.tar.gz 📎node_exporter-1.3.1.linux-amd64.tar.gz 📎prometheus-webhook-dingtalk-1.4.0.linux-amd64.tar.gz 服务端口 Prometheus 9090 node_exporter 9100 alertmanager …...

Java百度提前批面试题
今天分享百度提前批的 Java 后端开发面经,整体上考察的点挺多的,主要重点考察了网络i/o、网络协议、linux系统、mysql,Java 问的不多,可能是百度的后端开发的语言不是主要以 Java 为主,所以重点看面试者的计算机基础是…...

Go语言中的Oop面向对象
Go In OOp 一、 Go是面向对象的吗?二、Structs Instead of Classes 结构体 - OOP in Go三、 Composition Instead of Inheritance 组合嵌套 - OOP in Go1.Composition by embedding structs2. Embedding slice of structs 四、Polymorphism 多态 - OOP in Go1. Polymorphism u…...

Duplicate keys detected: ‘1‘. This may cause an update error.
报错 Duplicate keys detected: ‘1’. This may cause an update error. 注释: 检测到重复密钥:‘1’。这可能会导致更新错误。 解决 首先判断是因为for循环导致的,检查是否出现重复。 笔者是同一个页面两处for循环导致...

C++(8.21)c++初步
1.斐波那契: #include <iostream> #include<iomanip>using namespace std;int main() {cout << "Hello World!" << endl;int a[10];for(int i0;i<10;i){if(0i||1i){a[i]1;}elsea[i]a[i-1]a[i-2];cout <<setw(4) <&l…...

【【Verilog典型电路设计之log函数的Verilog HDL设计】】
Verilog典型电路设计之log函数的Verilog HDL设计 log函数是一种典型的单目计算函数,与其相应的还有指数函数、三角函数等。对于单目计算函数的硬件加速器设计一般两种简单方法:一种是查找表的方式;一种是使用泰勒级数展开成多项式进行近似计算。这两种方式在设计方…...

数字放大(C++)
系列文章目录 1.进阶的卡沙_睡觉觉觉得的博客-CSDN博客 2. 数1的个数_睡觉觉觉得的博客-CSDN博客 3. 双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客 4. 足球联赛积分_睡觉觉觉得的博客-CSDN博客 5. 大减价(一级)_睡觉觉觉得的博客-CSDN博客 6. 小写字母的判断_睡觉觉觉得…...

FOC控制框架图
pmsm电机数学模型以及FOC控制框图(开源小项目FOC控制BLDC电机)_foc 框图_栋哥爱做饭的博客-CSDN博客 电机控制----FOC框架讲解_foc电机控制_修才生的博客-CSDN博客...

Spring工具类(获取bean,发布事件)
spring-beans-5.3.1.jar Component public final class SpringUtils implements BeanFactoryPostProcessor{/*** Spring应用上下文环境*/private static ConfigurableListableBeanFactory beanFactory;//初始化成员变量Overridepublic void postProcessBeanFactory(Configurab…...

腾讯云和阿里云服务器折扣对比_看看哪家划算?
阿里云服务器和腾讯云服务器根据购买时长可以享受一定的优惠折扣,综合对比下来腾讯云折扣更低,阿腾云来对比下阿里云和腾讯云的云服务器根据购买时长可以享受的常规折扣对比: 目录 阿里云和腾讯云折扣对比 阿里云服务器常规折扣 腾讯云服…...

GO语言中的Defer与Error异常报错详细教程
目录标题 一、Defer1. Example2. Deferred methods 延迟方法3. Arguments evaluation 延迟参数4. Stack of defers 延迟程序堆栈5. Practical use of defer 实际使用 二、Error1. Example2. PathError3. DNSError4. Direct Comparison 直接比较5. Do not ignore errors 不要忽略…...

AP6315 DC单节锂电池充电IC 同步2A锂电芯片
概述 是一款面向5V交流适配器的2A锂离子电池充电器。它是采用1.5MHz固定频率的同步降压型转换器,因此具有高达90%以上的充电效率,自身发热量极小。包括完整的充电终止电路、自动再充电和一个达1%的4.2V预设充电电压,内部集成了防反灌保护、输…...

PDF校对工具正式上线,为用户提供卓越的文档校对解决方案
为满足当下对数字化文档校对的精准需求,我们今日正式发布全新的PDF校对工具。经过深入的技术研发与细致的测试,该工具旨在为企业和个人用户带来一个高效且准确的PDF文档校对平台。 PDF校对工具的主要特性: 1.全面性校对:工具支持…...

WSL 配置 Oracle 19c 客户端
Windows WSL 登陆后显示如下: Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 4.4.0-19041-Microsoft x86_64)* Documentation: https://help.ubuntu.com* Management: https://landscape.canonical.com* Support: https://ubuntu.com/advantageSystem information as…...

ChatGPT⼊门到精通(1):ChatGPT 是什么
⼀、直观感受 1、公司 OpenAI(美国) 2、官⽅⽹站 3、登录ChatGPT 
idea启动正常,打成jar包时,启动报错
背景 自己写了个小程序,在idea中启动正常,达成jar包发布时,启动报错。 Caused by: java.sql.SQLException: unknown jdbc driver : at com.alibaba.druid.util.JdbcUtils.getDriverClassName(JdbcUtils.java:517) at com.alibaba.druid.pool…...

软考高级系统架构设计师系列论文八十九:论软件需求分析方法和工具的选用
软考高级系统架构设计师系列论文八十九:论软件需求分析方法和工具的选用 一、软件需求相关知识点二、摘要三、正文四、总结一、软件需求相关知识点 软考高级系统架构设计师:论软件需求管理...

java八股文面试[JVM]——类加载器
一、类加载器的概念 类加载器是Java虚拟机用于加载类文件的一种机制。在Java中,每个类都由类加载器加载,并在运行时被创建为一个Class对象。类加载器负责从文件系统、网络或其他来源中加载类的字节码,并将其转换为可执行的Java对象。类加载器…...

CSS中如何实现元素之间的间距(Margin)合并效果?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 外边距合并的示例:⭐ 如何控制外边距合并:⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅ÿ…...

【实操干货】如何开始用Qt Widgets编程?(三)
Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 在本文中࿰…...

基于深度学习的图像风格迁移发展总结
前言 本文总结深度学习领域的图像风格迁移发展脉络。重点关注随着GAN、CUT、StyleGAN、CLIP、Diffusion Model 这些网络出现以来,图像风格迁移在其上的发展。本文注重这些网络对图像风格迁移任务的影响,以及背后的关键技术和研究,并总结出一…...

小程序页面间有哪些传递数据的方法?
使用全局变量实现数据传递 在 app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面使用的时候,直接使用 getApp() 拿到存储的信息 App({// 全局变量globalData: {userInfo: null} }) 使用 wx.navigateTo 与 wx.redirectTo 的时候&…...

bh002- Blazor hybrid / Maui 保存设置快速教程
1. 建立工程 bh002_ORM 源码 2. 添加 nuget 包 <PackageReference Include"BootstrapBlazor.WebAPI" Version"7.*" /> <PackageReference Include"FreeSql" Version"*" /> <PackageReference Include"FreeSql.…...

同源政策与CORS
CORS意为跨源资源共享(Cross origin resource sharing),它是一个W3C标准,由一系列HTTP Header组成,这些 HTTP Header决定了浏览器是否允许JavaScript 代码成功获得跨源请求的服务器响应。 在说CORS之前,先…...

科技资讯|三星再申请智能戒指商标,智能穿戴进入更小型化发展
三星正在积极扩展可穿戴设备生态,近日向英国知识产权局提交了名为“Samsung Curio”的新商标,其分类为“Class 9”,可能会用于未来的智能戒指。 智能戒指: 可穿戴计算机本质上的智能手环、智能项链、智能眼镜和智能戒指࿱…...

HarmonyOS开发第一步,熟知开发工具DevEco Studio
俗话说的好,工欲善其事,必先利其器,走进HarmonyOS第一步,开发工具必须先行,当然了,关于开发工具的使用,官网和其他的博客也有很多的讲解,但是并没有按照常用的功能进行概述ÿ…...

【应急响应】Linux常用基础命令
文章目录 文件和目录操作文件内容查看和编辑系统信息查询权限管理进程管理网络管理 文件和目录操作 ls:列出目录内容(例如 ls -l 显示详细信息) cd:切换工作目录 pwd:显示当前工作目录 touch:创建空文件&a…...

什么是Pytorch?
当谈及深度学习框架时,PyTorch 是当今备受欢迎的选择之一。作为一个开源的机器学习库,PyTorch 为研究人员和开发者们提供了一个强大的工具来构建、训练以及部署各种深度学习模型。你可能会问,PyTorch 是什么,它有什么特点…...