js之generate
generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。
ES6定义generator标准的哥们借鉴了Python的generator的概念和语法,如果你对Python的generator很熟悉,那么ES6的generator就是小菜一碟了。如果你对Python还不熟,赶快恶补Python教程!。
我们先复习函数的概念。一个函数是一段完整的代码,调用一个函数就是传入参数,然后返回结果:
function foo(x) {
return x + x;
}
var r = foo(1); // 调用foo函数
函数在执行过程中,如果没有遇到return语句(函数末尾如果没有return,就是隐含的return undefined;),控制权无法交回被调用的代码。
generator跟函数很像,定义如下:
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
generator和函数不同的是,generator由function*定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次。
大多数同学立刻就晕了,generator就是能够返回多次的“函数”?返回多次有啥用?
还是举个栗子吧。
我们以一个著名的斐波那契数列为例,它由0,1开头:
0 1 1 2 3 5 8 13 21 34 ...
要编写一个产生斐波那契数列的函数,可以这么写:
function fib(max) {
var
t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
[a, b] = [b, a + b];
arr.push(b);
}
return arr;
}
// 测试:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
函数只能返回一次,所以必须返回一个Array。但是,如果换成generator,就可以一次返回一个数,不断返回多次。用generator改写如下:
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
直接调用试试:
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
直接调用一个generator和调用函数不一样,fib(5)仅仅是创建了一个generator对象,还没有去执行它。
调用generator对象有两个方法,一是不断地调用generator对象的next()方法:
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果done为true,则value就是return的返回值。
当执行到done为true时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。
第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done:
'use strict'
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
enerator和普通函数相比,有什么用?
因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。例如,用一个对象来保存状态,得这么写:
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};
用对象的属性来保存状态,相当繁琐。
generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。这个好处要等到后面学了AJAX以后才能体会到。
没有generator之前的黑暗时代,用AJAX时需要这么写代码:
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});
回调越多,代码越难看。
有了generator的美好时代,用AJAX时可以这么写:
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}
看上去是同步的代码,实际执行是异步的。
js之generate的更多相关文章
- nuxt.js express模板项目服务器部署
nuxt版本:0.10.6 技术栈:nuxt.js, express, pm2 部署环境:windows server 之前用nuxt.js 的express的模板项目在windows下用nginx进 ...
- Optimize Cube.js Performance with Pre-Aggregations
转自:https://cube.dev/blog/high-performance-data-analytics-with-cubejs-pre-aggregations/ 可以了解 Pre-Aggr ...
- Frontend Development
原文链接: https://github.com/dypsilon/frontend-dev-bookmarks Frontend Development Looking for something ...
- What’s New In GRANDstack?
转自:https://blog.grandstack.io/whats-new-in-grandstack-310c067fea4a There’s been a lot of activity in ...
- 【咸鱼教程】protobuf在websocket通讯中的使用
教程目录一 protobuf简介二 使用protobuf三 Demo下载 参考: CSDN:Egret项目中使用protobuf(protobufjs) TS项目中使用Protobuf的解决方案(ba ...
- 在Android中使用Protocol Buffers(上篇)
本文来自网易云社区. 总览 先来看一下 FlatBuffers 项目已经为我们提供了什么,而我们在将 FlatBuffers 用到我们的项目中时又需要做什么的整体流程.如下图: 在使用 FlatBuf ...
- 在Android中使用FlatBuffers(上篇)
本文来自网易云社区. 总览 先来看一下 FlatBuffers 项目已经为我们提供了什么,而我们在将 FlatBuffers 用到我们的项目中时又需要做什么的整体流程.如下图: 在使用 FlatBuf ...
- [ubuntu篇] 使用Hexo建立个人博客,自定义域名https加密,搜索引擎google,baidu,360收录
为了更好的阅读体验,欢迎阅读原文.原文链接在此. Part 1: Using Github Pages and Hexo to manage personal blogs. Series Part 1 ...
- 83.基于Vue SEO的四种方案(小结)
前言:众所周知,Vue SPA单页面应用对SEO不友好,当然也有相应的解决方案,下面列出几种最近研究和使用过的SEO方案,SRR和静态化基于Nuxt来说. 1.SSR服务器渲染:2.静态化:3.预渲染 ...
随机推荐
- Django 实现上传图片功能
很多时候我们要用到图片上传功能,如果图片一直用放在别的网站上,通过加载网址的方式来显示的话其实也挺麻烦的,我们通过使用 django-filer 这个模块实现将图片文件直接放在自己的网站上. 感兴趣的 ...
- 题解 CF520E 【Pluses everywhere】
题目链接 ps:可能组合数一不小心打错了,请发现的大佬提出,谢谢. 我们来讨论每一位数$a_{i}$被算了多少次. 总共有$n-1$个空位可以放$'+'$所以,$a_{i}$左边有$i-1$个空位,右 ...
- 详细grep、sed、awk
[root@VM_0_7_centos tmp]# cat 1.txt 1 2 3 4 5 6 [root@VM_0_7_centos tmp]# cat 2.txt 4 5 6 7 8 [root@ ...
- Java面向对象之内部类(匿名内部类)
一.基础概念 匿名内部类:简化书写的内部类.其实匿名内部类就是一个子类对象. 前提:内部类需要继承或者实现外部的类或者接口. 格式:new 父类或者接口(){定义子类的内容} 二.将内部类定义到局部的 ...
- 八大排序算法的python实现(三)冒泡排序
代码: #coding:utf-8 #author:徐卜灵 #交换排序.冒泡排序 L = [1, 3, 2, 32, 5, 4] def Bubble_sort(L): for i in range( ...
- Python之路系列:面向对象初级:静态属性、静态方法、类方法
一.静态属性 静态属性相当于数据属性. 用@property语法糖装饰器将类的函数属性变成可以不用加括号直接的类似数据属性. 可以封装逻辑,让用户感觉是在调用一个普通的数据属性. 例子: class ...
- 5. 常见C语言字符串库函数的使用及实现
1. strncat 函数: [函数原型]#include <string.h> char *strncat( char *str1, const char *str2, size_t c ...
- 使用webpack开发ES6程序的正确姿势
1.cnpm install babel-loader babel-core babel-preset-es2015 -D 2.cnpm install babel-plugin-transform- ...
- iOS APP日志写入文件(日志收集)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...
- Qt C++ libcaffe.so无法调用
在用QT编写调用caffe的工程时,发现一直有个错误: error while loading shared libraries libcaffe.so.1.0.0-rc3: cannot open ...