ES6生成器函数generator
ES6生成器函数generator
generator是ES6新增的一个特殊函数,通过 function* 声明,函数体内通过 yield 来指明函数的暂停点,该函数返回一个迭代器,并且函数执行到 yield语句前面暂停,之后通过调用返回的迭代器next()方法来执行yield语句。
如下代码演示:
function* generator() {
yield 1;
yield 2;
yield 3;
}
var gen = generator();
如上代码:generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用generator函数后,该函数并不执行,返回的也不是函数运行的结果,而是一个指向内部状态的指针对象,我们可以通过调用next方法,使指针移向下一个状态。
console.log(gen.next()); // {value:1, done: false}
console.log(gen.next()); // {value:2, done: false}
console.log(gen.next()); // {value:3, done: false}
console.log(gen.next()); // {value: undefined, done: true}
如上代码,返回的迭代器每次调用next会返回一个对象 {value: "xxx", done: true/false}, value是返回值,done表示的是否达到迭代器的结尾,true是代表已经到了结尾,false代表没有。
我们可以通过 返回的对象的done是否为true来判断生成器是否执行结束,通过返回对象的value可以得到yield的返回值。如果返回对象的done值为true的话,那么该值value就为undefined。
迭代器next()方法还可以传入一个参数,这个参数会作为上一个yield语句的返回值,如果不传参数,yield语句中生成器函数内的返回值是 undefined。
如下代码演示:
function* test(x) {
let y = yield x;
console.log(1111)
yield y;
}
var t = test(3);
console.log(t.next()); // {value:3, done: false}
console.log(t.next()); // {value: undefined, done: false}
console.log(t.next()); // {value: undefined, done: true}
下面我们向第二个next方法传入值为5, 因此y的值被赋值为5,如下代码:
function* test(x) {
let y = yield x;
yield y;
}
var t = test(3);
console.log(t.next()); // {value:3, done: false}
console.log(t.next(5)); // {value: 5, done: false}
我们也可以通过 for...of循环可以自动遍历 generator函数生成对象,此时不需要调用next方法。如下代码:
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 4+1;
yield 6;
}
for (let v of foo()) {
console.log(v); // 1, 2, 3, 4, 5, 6
}
1-2 异常处理
下面是一个简单的列子来捕获generator里的异常
function* error() {
try {
throw new Error('error');
yield 11;
} catch(err) {
console.log(err);
}
}
var it = error();
it.next();
1-3 Generators的异步的应用
Generators 最主要的特点是单线程执行,同步风格代码编写,同时又允许将 代码异步的特性隐藏在程序的实现细节中。通过generators函数,我们将程序具体的实现细节从异步代码中抽离出来,可以很好的实现了功能和关注点的分离。
下面是使用ajax的demo,异步ajax请求,当请求完成后的数据,需要将返回的数据值传递给下一个请求去,也就是说下一个请求要依赖于上一个请求返回的数据依次传递下去代码如下:
function requestURL(url, cb) {
// ajax 请求, 请求完成后 调用cb函数
$.ajax({
url: url,
type: 'get',
dataType: 'json',
success: function(d) {
cb(d);
}
})
}
var url = 'http://httpbin.org/get';
requestURL(url, function(res) {
console.log(res);
var url2 = 'http://httpbin.org/get?origin='+res.origin;
requestURL(url2, function(res2) {
console.log(res2);
});
});
如上代码,我们看到异步ajax请求依次嵌套回调。
下面我们可以使用 generator去重新实现一下,如下代码:
function requestURL(url, cb) {
// ajax 请求, 请求完成后 调用cb函数
$.ajax({
url: url,
type: 'get',
dataType: 'json',
success: function(d) {
cb(d);
}
})
}
var url = 'http://httpbin.org/get';
function request(url) {
requestURL(url, function(res) {
it.next(res);
})
}
function* main() {
var res1 = yield request(url);
console.log(res1);
var res2 = yield request(url + '?origin='+res1.origin);
console.log(res2);
} var it = main();
it.next();
如上代码是使用Generator实现的异步代码请求;实现思路如下:
首先 requestURL 函数,发一个ajax请求,请求成功后调用回调函数 cb;request函数是封装requestURL函数,请求成功后回调,调用it.next()方法,
将指针指向下一个yield,main函数是请求启动代码,当 var it = main()时候,会调用main函数,但是只是会调用,但是并不会执行代码,因此需要 it.next()方法执行第一个 yield request(url) 方法,因此会调用request方法,再继续调用requestURL方法,最后会输出res1, 然后 requestURL方法的回调,又调用
it.next()方法,因此会执行main里面yield request的第二句代码,代码执行和第一次一样,最后输出res2.
上面的代码有一个地方需要理解的是,ajax请求成功以后 会继续调用 it.next()方法,那么成功后的数据如何传递到 res1呢?我们看到没有return语句返回的?
这是因为当 在ajax的callback调用的时候,它首先会传递ajax返回的结果。返回值发送到我们的generator时候,var res1 = yield request(url);给暂停了,然后在调用it.next()方法,会执行下一个请求。
1-4 Generator+Promise 实现异步请求
上面的generator代码可以做一些简单的异步请求,但是会受到一些限制,比如如下:
1. 没有明确的方法来处理请求error;ajax请求有时候会超时或失败的情况下,这个时候我们需要使用generator中的it.throw(),同时还需要使用try catch来处理错误的逻辑。
2. 一般情况下我们请求不会涉及到并行请求,但是如果有的需求是并行的话,比如说同时发2个或者多个ajax请求的话,由于 generator yidle机制都是逐步暂停的,无法同时运行另一个或多个任务,
因此,generator不太容易操作多个任务。
我们现在使用promise修改下 request的方法,让yield返回一个promise,所有代码如下:
function requestURL(url, cb) {
// ajax 请求, 请求完成后 调用cb函数
$.ajax({
url: url,
type: 'get',
dataType: 'json',
success: function(d) {
cb(d);
}
})
}
var url = 'http://httpbin.org/get';
function request(url) {
return new Promise((resolve, reject) => {
requestURL(url, resolve);
});
}
function runGenerator(cb) {
var it = cb(),
ret;
// 异步遍历generator
(function iterator(val){
console.log(111)
console.log(val); // undefined
// 返回一个promise
ret = it.next(val);
console.log(ret); // {value: Promise, done: false}
if (!ret.done) {
if('then' in ret.value) {
// 等待接受promise
ret.value.then(iterator);
} else {
setTimeout(function() {
iterator(ret.value);
}, 0)
}
}
})();
}
runGenerator(function *main() {
var res1 = yield request(url);
console.log(res1);
var res2 = yield request(url + '?origin='+res1.origin);
console.log(res2);
});
上面代码 :
function request(url) {
return new Promise((resolve, reject) => {
requestURL(url, resolve);
});
}
当ajax请求完成后,会返回这个promise,同时接收 yield request(url); 然后通过next()方法恢复generator运行,并把他们传递下去,第一次运行iterator方法后,val值为undefined,然后调用 ret = it.next(val); 返回一个promise ,继续打印下 console.log(ret); 返回如下: {value: Promise, done: false}
虽然上面代码运行正常,但是我们还未处理代码异常的情况下,因此下面处理下代码异常的情况下:
function requestURL(url, cb) {
// ajax 请求, 请求完成后 调用cb函数
$.ajax({
url: url,
type: 'get',
dataType: 'json',
success: function(d) {
cb(null, d);
},
error: function(err) {
cb(err, text);
}
})
}
var url = 'http://httpbin.org/get';
function request(url) {
return new Promise((resolve, reject) => {
requestURL(url, function(err, text){
if (err) {
reject(err);
} else {
resolve(text);
}
});
});
}
function runGenerator(cb) {
var it = cb(),
ret;
// 异步遍历generator
(function iterator(val){
console.log(111)
console.log(val); // undefined
// 返回一个promise
ret = it.next(val);
console.log(ret); // {value: Promise, done: false}
if (!ret.done) {
if('then' in ret.value) {
// 等待接受promise
ret.value.then(iterator);
} else {
setTimeout(function() {
iterator(ret.value);
}, 0)
}
}
})();
} runGenerator(function *main() {
try {
var res1 = yield request(url);
} catch(err) {
console.log(err);
return;
}
console.log(res1);
try {
var res2 = yield request(url + '?origin='+res1.origin);
} catch(err) {
console.log(err);
return;
}
console.log(res2);
})
第一步处理异常的情况下 代码如上已经完成了,现在来解决第二步 使用Promise + generator 解决多个请求同时运行,需要使用Promise.all()方法来解决。
如下代码:
function requestURL(url, cb) {
// ajax 请求, 请求完成后 调用cb函数
$.ajax({
url: url,
type: 'get',
dataType: 'json',
success: function(d) {
cb(null, d);
},
error: function(err) {
cb(err, text);
}
})
}
var url = 'http://httpbin.org/get';
function request(url) {
return new Promise((resolve, reject) => {
requestURL(url, function(err, text){
if (err) {
reject(err);
} else {
resolve(text);
}
});
})
// 获取返回值后
.then(function(d) {
console.log('dddddd');
console.log(d);
return d
});
}
function runGenerator(cb) {
var it = cb(),
ret;
// 异步遍历generator
(function iterator(val){
// 返回一个promise
ret = it.next(val);
if (!ret.done) {
if('then' in ret.value) {
// 等待接受promise
ret.value.then(iterator);
} else {
setTimeout(function() {
iterator(ret.value);
}, 0)
}
}
})();
} runGenerator(function *main() {
var res1 = yield Promise.all([
request(url),
request(url)
]);
console.log(2222)
console.log(res1);
var result = yield request(url + '?origin='+res1[0].origin);
console.log(result);
})
ES6生成器函数generator的更多相关文章
- ES6新特性之生成器函数 (generator function): function*
一.什么是生成器函数(generator function)? 生成器函数是ES6的新特性之一,它是一个在执行时能中途暂时退出,后面重新调用又能重新进入继续执行的一种函数. 并且在函数内定义的变量的所 ...
- 一种特殊的生成器函数-Generator函数
本节的内容,是建立在iterator遍历器知识的基础上.所以希望还没有看上一节的内容的话,最好还是看一看,当然你如果熟悉iterator就没有那个必要了. 既然你都看到这里来了,就咱们就接着往下讲.. ...
- 学习ES6生成器(Generator)
背景 在JS的使用场景中,异步操作的处理是一个不可回避的问题,如果不做任何抽象.组织,只是“跟着感觉走”,那么面对“按顺序发起3个ajax请求”的需求,很容易就能写出如下代码(假设已引入jQuery) ...
- [ES6系列-07]Generator Function: 生成器函数
[原创]码路工人 Coder-Power 大家好,这里是码路工人有力量,我是码路工人,你们是力量. github-pages 博客园cnblogs Generator function 生成器函数是E ...
- 石川es6课程---13-16、generator-认识生成器函数
石川es6课程---13-16.generator-认识生成器函数 一.总结 一句话总结: ` generator函数,中间可以停,到哪停呢,用 yield 配合,交出执行权 ` 需要调用next() ...
- ES6生成器基础
ES6引进的最令人兴奋的特性就是一种新的函数生成方式,称为生成器(generator).名称有点奇怪,但是第一眼看上去行为更加奇怪.文章主要介绍生成器如何工作,然后让你明白为什么他们对于未来的JS会有 ...
- Javascript生成器函数
function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个Generator 对象 示例: function* g ...
- ES6笔记(5)-- Generator生成器函数
系列文章 -- ES6笔记系列 接触过Ajax请求的会遇到过异步调用的问题,为了保证调用顺序的正确性,一般我们会在回调函数中调用,也有用到一些新的解决方案如Promise相关的技术. 在异步编程中,还 ...
- ES6新特性三: Generator(生成器)函数详解
本文实例讲述了ES6新特性三: Generator(生成器)函数.分享给大家供大家参考,具体如下: 1. 简介 ① 理解:可以把它理解成一个函数的内部状态的遍历器,每调用一次,函数的内部状态发生一次改 ...
随机推荐
- lucene 核心概念及入门
lucene Lucene介绍及核心概念 什么是Lucene Lucene是一套用于全文检索和搜索的开放源代码程序库,由Apache软件基金会支持和提供.Lucene提供了一个简单却强大的应用程序接口 ...
- 微信跳一跳Python辅助无需配置一键操作
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8350329.html 邮箱:moyi@moyib ...
- 每个JavaScript工程师都应懂的33个概念
摘要: 基础很重要啊! 原文:33 concepts every JavaScript developer should know 译文:每个 JavaScript 工程师都应懂的33个概念 作者:s ...
- lnmp首次安装重置mysql密码
第一种方法:一键修改LNMP环境下MYSQL数据库密码脚本 一键脚本肯定是非常方便.具体执行以下命令: wget http://soft.vpser.net/lnmp/ext/reset_mysql_ ...
- 设置div背景透明的CSS样式
div背景透明样式: 样式代码: .alert{filter:alpha(opacity=100); /* IE */ -moz-opacity:1.0; /* Moz + FF */ opacity ...
- VUE页面刷新问题
1). location方式 location.reload() 缺点:刷新页面,卡白 2). router方式 this.$router.go(0) 缺点:同一问题,比一好点 3). provide ...
- loj#2002. 「SDOI2017」序列计数(dp 矩阵乘法)
题意 题目链接 Sol 质数的限制并没有什么卵用,直接容斥一下:答案 = 忽略质数总的方案 - 没有质数的方案 那么直接dp,设\(f[i][j]\)表示到第i个位置,当前和为j的方案数 \(f[i ...
- 获取url参数的方法(web)
//获取url参数的方法(web) function GetQueryString(name) { var reg = new RegExp("(^|&)" + n ...
- python自动化开发-9 进程 线程
进程与线程 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一 ...
- python自动化开发-7
socket编程 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对 ...