ES6基础知识七:你是怎么理解ES6中 Generator的?使用场景?

在这里插入图片描述
一、介绍

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同

回顾下上文提到的解决异步的手段:

  • 回调函数
  • promise

那么,上文我们提到promsie已经是一种比较流行的解决异步方案,那么为什么还出现Generator?甚至async/await呢?

该问题我们留在后面再进行分析,下面先认识下Generator

Generator函数

执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态

形式上,Generator函数是一个普通函数,但是有两个特征:

  • function关键字与函数名之间有一个星号
  • 函数体内部使用yield表达式,定义不同的内部状态
function* helloWorldGenerator() {yield 'hello';yield 'world';return 'ending';
}

二、使用

Generator 函数会返回一个遍历器对象,即具有Symbol.iterator属性,并且返回给自己

function* gen(){// some code
}var g = gen();g[Symbol.iterator]() === g
// true

通过yield关键字可以暂停generator函数返回的遍历器对象的状态

function* helloWorldGenerator() {yield 'hello';yield 'world';return 'ending';
}
var hw = helloWorldGenerator();

上述存在三个状态:hello、world、return

通过next方法才会遍历到下一个内部状态,其运行逻辑如下:

  • 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
  • 一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式
  • 如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
  • 如果该函数没有return语句,则返回的对象的value属性值为undefined
hw.next()
// { value: 'hello', done: false }hw.next()
// { value: 'world', done: false }hw.next()
// { value: 'ending', done: true }hw.next()
// { value: undefined, done: true }

done用来判断是否存在下个状态,value对应状态值

yield表达式本身没有返回值,或者说总是返回undefined

通过调用next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值

function* foo(x) {var y = 2 * (yield (x + 1));var z = yield (y / 3);return (x + y + z);
}var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

正因为Generator函数返回Iterator对象,因此我们还可以通过for…of进行遍历

function* foo() {yield 1;yield 2;yield 3;yield 4;yield 5;return 6;
}for (let v of foo()) {console.log(v);
}
// 1 2 3 4 5

原生对象没有遍历接口,通过Generator函数为它加上这个接口,就能使用for…of进行遍历了

function* objectEntries(obj) {let propKeys = Reflect.ownKeys(obj);for (let propKey of propKeys) {yield [propKey, obj[propKey]];}
}let jane = { first: 'Jane', last: 'Doe' };for (let [key, value] of objectEntries(jane)) {console.log(`${key}: ${value}`);
}
// first: Jane
// last: Doe

三、异步解决方案

回顾之前展开异步解决的方案:

  • 回调函数
  • Promise 对象
  • generator 函数
  • async/await

这里通过文件读取案例,将几种解决异步的方案进行一个比较:

回调函数

所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数

fs.readFile('/etc/fstab', function (err, data) {if (err) throw err;console.log(data);fs.readFile('/etc/shells', function (err, data) {if (err) throw err;console.log(data);});
});

readFile函数的第三个参数,就是回调函数,等到操作系统返回了/etc/passwd这个文件以后,回调函数才会执行

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)
})

这种链式操作形式,使异步任务的两段执行更清楚了,但是也存在了很明显的问题,代码变得冗杂了,语义化并不强

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());
};

async/await

将上面Generator函数改成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());
};

区别:

通过上述代码进行分析,将promise、Generator、async/await进行比较:

  • promise和async/await是专门用于处理异步操作的
  • Generator并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署Interator接口…)
  • promise编写代码相比Generator、async更为复杂化,且可读性也稍差
  • Generator、async需要与promise对象搭配处理异步情况
  • async实质是Generator的语法糖,相当于会自动执行Generator函数
  • async使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案

四、使用场景

Generator是异步解决的一种方案,最大特点则是将异步操作同步化表达出来

function* loadUI() {showLoadingScreen();yield loadUIDataAsynchronously();hideLoadingScreen();
}
var loader = loadUI();
// 加载UI
loader.next()// 卸载UI
loader.next()

包括redux-saga中间件也充分利用了Generator特性

import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'function* fetchUser(action) {try {const user = yield call(Api.fetchUser, action.payload.userId);yield put({type: "USER_FETCH_SUCCEEDED", user: user});} catch (e) {yield put({type: "USER_FETCH_FAILED", message: e.message});}
}function* mySaga() {yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}function* mySaga() {yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}export default mySaga;

还能利用Generator函数,在对象上实现Iterator接口

function* iterEntries(obj) {let keys = Object.keys(obj);for (let i=0; i < keys.length; i++) {let key = keys[i];yield [key, obj[key]];}
}let myObj = { foo: 3, bar: 7 };for (let [key, value] of iterEntries(myObj)) {console.log(key, value);
}// foo 3
// bar 7

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/8003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter中如何取消任务

前言 在开发过程中&#xff0c;取消需求是很常见的&#xff0c;但很容易被忽略。然而&#xff0c;取消需求的好处也很大。例如&#xff0c;在页面中会发送很多请求。如果页面被切走并处于不可见状态&#xff0c;就需要取消未完成的请求任务。如果未及时取消&#xff0c;则可能…

Android平台GB28181设备接入模块之按需编码和双码流编码

技术背景 我们在做执法记录仪或指挥系统的时候&#xff0c;会遇到这样的情况&#xff0c;大多场景下&#xff0c;我们是不需要把设备端的数据&#xff0c;实时传给国标平台端的&#xff0c;默认只需要本地录像留底&#xff0c;如果指挥中心需要查看前端设备实时数据的时候&…

Python实现九宫格数独小游戏

1 问题 有1-9个数字&#xff0c;将他们填入一个3*3的九宫格中&#xff0c;使得他们的每行&#xff0c;每列&#xff0c;以及对角线上的和相等&#xff0c;且要求每个格子的数字不可以重复。使用python列出所有可能的组合。示例如下: 2 方法 每行&#xff0c;列&#xff0c;对角…

临时文档4

Redis有哪些数据类型 Redis主要有5种数据类型&#xff0c;包括String&#xff0c;List&#xff0c;Set&#xff0c;Zset&#xff0c;Hash&#xff0c;满足大部分的使用要求 Redis的应用场景 总结一 计数器 可以对 String 进行自增自减运算&#xff0c;从而实现计数器功能。…

uni-app优雅的实现时间戳转换日期格式

现在显示的格式如下图&#xff1a; 我期望统一格式&#xff0c;所以不妨前端处理一下&#xff0c;核心代码如下 filters: {// 时间戳处理formatDate: function(value, spe /) {value value * 1000let data new Date(value);let year data.getFullYear();let month data.…

微信认证申请流程(个体工商户)

登录微信公众平台->设置->微信认证->开通 第一步&#xff1a;同意协议&#xff1a;签署《微信公众平台认证服务协议》 第二步&#xff1a;选择认证类型及填写认证资料 选择认证类型及上传申请公函 个体户资质信息 认证联系人信息&#xff1a;个体工商户联系人必须为法…

【如何训练一个中译英翻译器】LSTM机器翻译模型部署之ncnn(python)(五)

系列文章 【如何训练一个中译英翻译器】LSTM机器翻译seq2seq字符编码&#xff08;一&#xff09; 【如何训练一个中译英翻译器】LSTM机器翻译模型训练与保存&#xff08;二&#xff09; 【如何训练一个中译英翻译器】LSTM机器翻译模型部署&#xff08;三&#xff09; 【如何训练…

【优选算法题练习】day8

文章目录 一、974. 和可被 K 整除的子数组1.题目简介2.解题思路3.代码4.运行结果 二、525. 连续数组1.题目简介2.解题思路3.代码4.运行结果 三、560. 和为 K 的子数组1.题目简介2.解题思路3.代码4.运行结果 总结 一、974. 和可被 K 整除的子数组 1.题目简介 974. 和可被 K 整…

【设计模式】单例设计模式详解(包含并发、JVM)

文章目录 1、背景2、单例模式3、代码实现1、第一种实现&#xff08;饿汉式&#xff09;为什么属性都是static的&#xff1f;2、第二种实现&#xff08;懒汉式&#xff0c;线程不安全&#xff09;3、第三种实现&#xff08;懒汉式&#xff0c;线程安全&#xff09;4、第四种实现…

day38-Mobile Tab Navigation(手机tab栏导航切换)

50 天学习 50 个项目 - HTMLCSS and JavaScript day38-Mobile Tab Navigation&#xff08;手机tab栏导航切换&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"…

3ds MAX 洗菜池

在家居中我们显然离不开这个对吧 首先绘制一个长方体作为基础 注意设置长宽高的网格大小&#xff0c;方便后续调整 俯视图网格线如下&#xff1a; 长方形变换为可编辑网络&#xff0c;并在【多边形】界面选择底面的所有多边形&#xff0c;按delete删除&#xff0c;形成一个壳体…

Github上方导航栏介绍

Code Watch&#xff1a;相当于关注&#xff0c;到时候这个项目又有什么操作&#xff0c;就会以通知的形式提醒你。 Fork&#xff1a;也就是把这个项目拉到你的仓库里&#xff0c;之后你可以对该代码进行修改&#xff0c;之后你可以发起Pull Request&#xff0c;简称PR&#xf…

vulnhub靶场之CengBox3

1.信息收集 输入命令&#xff1a;netdiscover -i eth0 -r 192.168.239.0 &#xff0c;发现181机器存活 输入命令nmap -p- -sV -O -Pn -A 192.168.239.181 &#xff0c;进行端口探测&#xff0c;发现存在22、80、443端口&#xff0c;还发现存在域名ceng-company.vm。 将域名c…

了解Unity编辑器之组件篇Tilemap(五)

Tilemap&#xff1a;用于创建和编辑2D网格地图的工具。Tilemap的主要作用是简化2D游戏中地图的创建、编辑和渲染过程。以下是一些Tilemap的主要用途&#xff1a; 2D地图绘制&#xff1a;Tilemap提供了一个可视化的编辑器界面&#xff0c;可以快速绘制2D地图&#xff0c;例如迷…

python实现逻辑回归-清风数学建模-二分类水果数据

所用数据 &#x1f449;&#x1f449;&#x1f449;二分类水果数据 1.数据预处理 可以看到有4个特征&#xff0c;2种分类结果&#xff0c;最后4个没有分类结果的数据是拿来预测的 # 1. 数据预处理 import pandas as pd df pd.read_excel(oridata/二分类水果数据.xlsx,use…

开源大模型LLaMA 2会扮演类似Android的角色么?

在AI大模型没有商业模式&#xff1f;等文章中&#xff0c;我多次表达过这样一个观点&#xff1a;不要把大模型的未来应用方式比喻成公有云&#xff0c;大模型最终会是云端操作系统的核心&#xff08;新通用计算平台&#xff09;&#xff0c;而它的落地形式会很像过去的沃森&…

【C++】开源:Linux端ALSA音频处理库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端ALSA音频处理库。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

Python增删改查小练习

目录 1. List操作-增加 2. List操作-查询 3. List操作-修改 4. List操作-删除 资料获取方法 1. List操作-增加 List Append(“xx”) 插入到列表尾部 Insert(x,xx) 在指定的位置插入 Extend 将列表的元素分开,插入到之前列表的尾部 小练习: 把一个字符串”abcdefg…

ssh打开远程vscode

如果想要远程打开其他终端的vscode&#xff0c;首先要知道远程终端的ip地址和用户名称以及用户密码 1、打开本地vscode 2、点击左下角蓝色区域 3、页面上部出现如下图&#xff0c;点击ssh&#xff0c;我这里已经连接&#xff0c;所以是connect to host 4、选择Add New SSH Host…

appium中toast识别

目录 一、什么是Toast&#xff1f; 二、环境前提 三、修改配置 四、安装驱动 五、常见报错及解决方案 1、cnpm 不识别&#xff0c;提示不是内部或外部命令 2、npm 也不识别 3、报错 六、代码节选 一、什么是Toast&#xff1f; Android中的Toast是一种简易的消息提示框…