一次搞懂 Generator 函数
1、什么是 Generator 函数
在Javascript中,一个函数一旦开始执行,就会运行到最后或遇到return时结束,运行期间不会有其它代码能够打断它,也不能从外部再传入值到函数体内
而Generator函数(生成器)的出现使得打破函数的完整运行成为了可能,其语法行为与传统函数完全不同
{
// 传统函数
function foo() {
return 'hello world'
} foo() // 'hello world',一旦调用立即执行 // Generator函数
function* generator() {
yield 'status one' // yield 表达式是暂停执行的标记
return 'hello world'
} let iterator = generator() // 调用 Generator函数,函数并没有执行,返回的是一个Iterator对象
iterator.next() // {value: "status one", done: false},value 表示返回值,done 表示遍历还没有结束
iterator.next() // {value: "hello world", done: true},value 表示返回值,done 表示遍历结束
}
{
function* gen() {
yield 'hello'
yield 'world'
return 'ending'
} let it = gen() it.next() // {value: "hello", done: false}
it.next() // {value: "world", done: false}
it.next() // {value: "ending", done: true}
it.next() // {value: undefined, done: true}
}
{
(function (){
yield 1;
})() // SyntaxError: Unexpected number
// 在一个普通函数中使用yield表达式,结果产生一个句法错误
}
{
function* demo() {
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
}
}
{
function* demo() {
foo(yield 'a', yield 'b'); // OK
let input = yield; // OK
}
}
{
function* foo() {
yield 'aaa'
yield 'bbb'
} function* bar() {
foo()
yield 'ccc'
yield 'ddd'
} let iterator = bar() for(let value of iterator) {
console.log(value)
} // ccc
// ddd }
{
function* foo() {
yield 'aaa'
yield 'bbb'
} function* bar() {
yield* foo() // 在bar函数中 **执行** foo函数
yield 'ccc'
yield 'ddd'
} let iterator = bar() for(let value of iterator) {
console.log(value)
} // aaa
// bbb
// ccc
// ddd
}
[rv] = yield [expression] expression:定义通过遍历器从生成器函数返回的值,如果省略,则返回 undefined
rv:接收从下一个 next() 方法传递来的参数
{
function* gen() {
let result = yield 3 + 5 + 6
console.log(result)
yield result
} let it = gen()
console.log(it.next()) // {value: 14, done: false}
console.log(it.next()) // undefined {value: undefined, done: false}
}

{
function* gen() {
let result = yield 3 + 5 + 6
console.log(result)
yield result
} let it = gen()
console.log(it.next()) // {value: 14, done: false}
console.log(it.next(3)) // 3 {value: 3, done: false}
}
{
function* gen() {
let result = yield 3 + 5 + 6
console.log(result)
yield result
} let it = gen()
console.log(it.next(10)) // {value: 14, done: false}
console.log(it.next(3)) // 3 {value: 3, done: false}
}
{
function* gen(x) {
let y = 2 * (yield (x + 1)) // 注意:yield 表达式如果用在另一个表达式中,必须放在圆括号里面
let z = yield (y / 3)
return x + y + z
} let it = gen(5)
/* 通过前面的介绍就知道这部分输出结果是错误的啦 console.log(it.next()) // {value: 6, done: false}
console.log(it.next()) // {value: 2, done: false}
console.log(it.next()) // {value: 13, done: false}
*/ /*** 正确的结果在这里 ***/
console.log(it.next()) // 首次调用next,函数只会执行到 “yield(5+1)” 暂停,并返回 {value: 6, done: false}
console.log(it.next()) // 第二次调用next,没有传递参数,所以 y的值是undefined,那么 y/3 当然是一个NaN,所以应该返回 {value: NaN, done: false}
console.log(it.next()) // 同样的道理,z也是undefined,6 + undefined + undefined = NaN,返回 {value: NaN, done: true}
}
{
function* gen(x) {
let y = 2 * (yield (x + 1)) // 注意:yield 表达式如果用在另一个表达式中,必须放在圆括号里面
let z = yield (y / 3)
return x + y + z
} let it = gen(5) console.log(it.next()) // 正常的运算应该是先执行圆括号内的计算,再去乘以2,由于圆括号内被 yield 返回 5 + 1 的结果并暂停,所以返回{value: 6, done: false}
console.log(it.next(9)) // 上次是在圆括号内部暂停的,所以第二次调用 next方法应该从圆括号里面开始,就变成了 let y = 2 * (9),y被赋值为18,所以第二次返回的应该是 18/3的结果 {value: 6, done: false}
console.log(it.next(2)) // 参数2被赋值给了 z,最终 x + y + z = 5 + 18 + 2 = 25,返回 {value: 25, done: true}
}
{
function* gen(x) {
let y = 2 * (yield (x + 1))
let z = yield (y / 3)
z = 88 // 注意看这里
return x + y + z
} let it = gen(5) console.log(it.next()) // {value: 6, done: false}
console.log(it.next(9)) // {value: 6, done: false}
console.log(it.next(2)) // 这里其实也很容易理解,参数2被赋值给了 z,但是函数体内又给 z 重新赋值为88, 最终 x + y + z = 5 + 18 + 88 = 111,返回 {value: 111, done: true}
}
5、与 Iterator 接口的关系
{
let obj = {} function* gen() {
yield 4
yield 5
yield 6
} obj[Symbol.iterator] = gen for(let value of obj) {
console.log(value)
}
//
//
// console.log([...obj]) // [4, 5, 6]
}
{
function* gen() {
yield 1
yield 2
yield 3
yield 4
return 5
} for(let item of gen()) {
console.log(item)
} // 1 2 3 4
}
{
function* gen() {
yield 1
yield 2
yield 3
} let it = gen() it.next() // {value: 1, done: false}
it.return('ending') // {value: "ending", done: true}
it.next() // {value: undefined, done: true}
}
{
let count = 6 // 声明一个全局变量 // 具体抽奖逻辑的方法
function draw() {
// 执行一段抽奖逻辑
// ...
// 执行完毕 console.log(`剩余${count}次`)
} // 执行抽奖的方法
function startDrawing(){
if(count > 0) {
count--
draw(count)
}
} let btn = document.createElement('button')
btn.id = 'start'
btn.textContent = '开始抽奖'
document.body.appendChild(btn) document.getElementById('start').addEventListener('click', function(){
startDrawing()
}, false) }
{
// 具体抽奖逻辑的方法
function draw(count) {
// 执行一段抽奖逻辑
// ... console.log(`剩余${count}次`)
} // 执行抽奖的方法
function* remain(count) {
while(count > 0) {
count--
yield draw(count)
}
} let startDrawing = remain(6) let btn = document.createElement('button')
btn.id = 'start'
btn.textContent = '开始抽奖'
document.body.appendChild(btn) document.getElementById('start').addEventListener('click', function(){
startDrawing.next()
}, false)
}
{
// 请求的方法
function* ajax() {
yield new Promise((resolve, reject) => {
// 此处用一个定时器来模拟请求数据的耗时,并约定当返回的json中code为0表示有新数据更新
setTimeout(() => {
resolve({code: 0})
}, 200)
})
} // 长轮询的方法
function update() {
let promise = ajax().next().value // 返回的对象的value属性是一个 Promise 实例对象
promise.then(res => {
if(res.code != 0) {
setTimeout(() => {
console.log('2秒后继续查询.....')
update()
}, 2000)
} else{
console.log(res)
}
})
} update()
}
一次搞懂 Generator 函数的更多相关文章
- 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!
Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...
- 【转】一文搞懂C语言回调函数
转:https://segmentfault.com/a/1190000008293902?utm_source=tag-newest 什么是回调函数 我们先来看看百度百科是如何定义回调函数的: 回调 ...
- 来一轮带注释的demo,彻底搞懂javascript中的replace函数
javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...
- 终于搞懂了vue 的 render 函数(一) -_-|||
终于搞懂了vue 的 render 函数(一) -_-|||:https://blog.csdn.net/sansan_7957/article/details/83014838 render: h ...
- es6 --- Generator 函数
第一部分,ES6 中的 Generator 在 ES6 出现之前,基本都是各式各样类似Promise的解决方案来处理异步操作的代码逻辑,但是 ES6 的Generator却给异步操作又提供了新的思路, ...
- 彻底搞懂Javascript的“==”
本文转载自:@manxisuo的<通过一张简单的图,让你彻底地.永久地搞懂JS的==运算>. 大家知道,==是JavaScript中比较复杂的一个运算符.它的运算规则奇怪,容让人犯错,从而 ...
- 完全搞懂傅里叶变换和小波(1)——总纲<转载>
无论是学习信号处理,还是做图像.音视频处理方面的研究,你永远避不开的一个内容,就是傅里叶变换和小波.但是这两个东西其实并不容易弄懂,或者说其实是非常抽象和晦涩的! 完全搞懂傅里叶变换和小波,你至少需要 ...
- 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码
程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...
- 一天搞懂深度学习-训练深度神经网络(DNN)的要点
前言 这是<一天搞懂深度学习>的第二部分 一.选择合适的损失函数 典型的损失函数有平方误差损失函数和交叉熵损失函数. 交叉熵损失函数: 选择不同的损失函数会有不同的训练效果 二.mini- ...
随机推荐
- 实现CString的Format功能,支持跨平台
#include <string>#include <stdio.h> #include <stdarg.h> std::string& std_strin ...
- self-sizing cell的一个问题
如何TableViewCell里面再加上CollectionView这类的ScrollView玩意,那自动算高就失效了,还是得用 override func tableView(_ tableView ...
- Django用普通user对象登录的必须准备步骤
zt from http://segmentfault.com/q/1010000000343563 在stackoverflow找到了解答(http://stackoverflow.com/ques ...
- MySQL快速生成本地测试数据
利用数据的存储过程生成测试数据: 我们可以通过数据库的的 INSERT 语句直接在存储过程中向普通数据表中添加数据,但是 当我们添加到百万数据后,往普通表插入测试数据的性能就会明显降低.所以在这里建议 ...
- JAVA中Sql时间格式与util时间格式转换
关于时间格式转化: java.util.Date 与 java.sql.Date 互换 sql是子类 字符串转化成java.util.Date SimpleDateFormat date =n ...
- Hive入门学习--HIve简介
现在想要应聘大数据分析或者数据挖掘岗位,很多都需要会使用Hive,Mapreduce,Hadoop等这些大数据分析技术.为了充实自己就先从简单的Hive开始吧.接下来的几篇文章是记录我如何入门学习Hi ...
- 原生Feign使用详解
一,简介 Feign使得 Java HTTP 客户端编写更方便.Feign 灵感来源于Retrofit.JAXRS-2.0和WebSocket.Feign最初是为了降低统一绑定Denominator到 ...
- 用shell处理以下内容 1、按单词出现频率降序排序! 2、按字母出现频率降序排序! the squid project provides a number of resources toassist users design,implement and support squid installations. Please browsethe documentation and support
此题目有多种解法,sed.awk.tr等等,都可以解决此题,命令运用灵活多变. 编写shell脚本no_20.sh 解法1: #!/bin/bash ###-------------CopyRight ...
- Activity的状态保存
这两个图其实说的是一个意思,具体onSaveInstanceState()这个函数什么时候会调用,在网络上搜了一下 这个第一种情况,我可以解释一下,说的是这个方法只在onResume和onPause之 ...
- Django 的数据库查询
class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def _ ...