前言 大家都知道,Javascript是单线程、顺序执行的,通过事件循环来处理异步。而且稍有开发经验的同学也知道,利用setTimeout、setInterval以及Promise可以延时代码的执行。
顺晟科技
2021-06-16 10:58:32
245
最近,一个关于RSS聚合器的爬虫涉及到前端的redux-saga。用ES6中介绍的Generator很花俏,好像有雾。其实从思维和写作上来说基本和Python的生成器和产量一样。我之前已经用Python写了用法,这里简单的用动态语言写下我对生成器的学习和理解。
常识
首先,生成器本质上是一个函数,但是它的行为略有特殊。
普通函数会在执行结束时通过return返回;
生成器可以中断函数的执行过程,返回断点处继续执行。具体实现是通过yield和interrupt将结果返回给调用者,然后通过next()方法继续返回断点,再执行到下一个yield断点。
普通函数只返回一次,即执行结束;生成器函数在执行过程中可以多次返回,也就是说,它在产出断点处替换返回。
与生成器密切相关的另一个概念是迭代器。简单描述两者之间的关系,就是生成器实现的目的是生成迭代器,迭代器是可重复的,也就是可以循环遍历。
ES6
JavaScript ES6的生成器和普通函数最明显的区别在于,它的关键字包括星号*和yield,比如MDN文档上的代码示例:
函数*生成器(i) {
产量I;
产量i10;
}
var gen=发电机(10);
console.log(gen.next()。值);
//预期输出: 10
console.log(gen.next()。值);
//预期输出: 20
让我们看看上面的代码发生了什么事
function* generator(i) {}代码块声明了一个生成器,此时没有任何事情发生;
Var gen=generator(10)创建一个生成器并将其分配给变量gen
调用gen.next()时。值时,被执行的生成器进入个让步位置,中断执行并返回I,即10;
调用gen.next()时。第二次取值,回到发生器断点处继续执行,直到第二次屈服再次中断,返回i 10,即20;
可以预期,如果调用gen.next()。值,您将得到未定义的,因为这个生成器已经完成了所有断点,并在您第二次调用它时完成了“生成”任务。
请注意下一个()方法,它返回一个具有两个属性的JSON对象:
{
value:对象,
done:布尔值
}
值是生成器在迭代器中创建的元素,完成表示迭代器是否完成。
看看生成器的经典场景,生成斐波那契序列。
//生成器模式
函数* genFib(n) {
产量a=0
b=1
while(b=n) {
产量b
b=b a
a=b - a
}
}
var fib=genFib(100)
for(让fib值){
console.log(值)
}
从前面的过程分析来看,这个斐波那契序列生成过程非常容易理解。
换句话说,如果斐波那契序列是由普通的循环迭代生成的,一般类似于下面的代码。
//循环模式
函数genFib(n) {
假设a=0
让b=1
让fib=[0]
while(b=n) {
fib.push(b)
b=b a
a=b - a
}
返回纤维
}
乍一看,似乎两者只是写法不同,实际运行速度并没有因为样本量太小而有所不同。但仔细观察后不难发现,第二次循环迭代会将所有结果存储在内存中,只有完全生成后才会返回;个生成器被编写为一次只生成一个元素,并立即返回。当数量n较大时,发生器的资源和性能增益相当大。
JavaScript就像一匹脱缰的野马。它的语法太灵活了。有很多种写法会让程序员觉得很奇怪,比如yield*的用法。这个表达其实是用来把一个发电机托付给另一个发电机,笑哭…….
例如,在前面的例子中,生成器被分配给一个普通变量,yield* [[expression]]是对右表达式的生成器的每个元素进行yield。
function* gen1() {
产量1;
产量2;
产量3;
}
function* gen2() {
yield * gen 1();
产量4;
}
[.gen 2()];
//[ 1, 2, 3, 4 ]
JavaScript中有字符串、数组、类型、映射、集合等支持可迭代的。因此,这些内置对象也支持产量*表达式、for-of表达式和.表达式,非常灵活。
理解JavaScript ES6中的生成器,更容易理解redux-saga的状态管理,有空再写redux-saga。
计算机编程语言
Python中的生成器和JavaScript基本相同。或者以斐波那契为例。
def gen_fib(n):
产量0
a,b=0,1
而b=n:
产量b
b=b a
a=b - a
对于gen_fib(100):中的值
打印(数值)
Python版本只添加了yield关键字,没有设计*来表示声明函数的生成器。
之前的博客理解Python生成器很浅,所以在这里我尝试从Magic Method写的更深一些。
Python内置了一些叫做Magic Method的特殊方法,比如__init__,__new__,__str__。这些Magic Method的初衷是描述对象的内在行为,而不需要外部的显式调用。例如,我们声明一个对象并编写它的__init__方法:
class Book:
def __init__(自我,姓名,作者):
self.name=name
self.author=作者
书=书(《哈利波特》,《罗琳》)
书。__getattribute__('name ')
书。__getattribute__(“作者”)
我们没有直接调用__init__方法,但是Python解释可以理解并调用__init__初始化对象。
16
2021-06
16
2021-06
16
2021-06
16
2021-06
16
2021-06
16
2021-06