- Grenerator的语法和普通的函数是完全不同的,Grenerator在执行时可以暂停,然后可以在暂停的位置继续执行。就是一步一步的执行。
- 不能做为构造函数使用,只能返回一个生成器对象
- Grenerator函数的特点是function后面有一个“ * ”号,一般function和*紧挨在一起。
通过下面的输出可以看到,仅返回了一个Generator函数,而且for循环没有被执行,这是因为gererator函数需要手动执行
// 一般function和*紧挨在一起
function* foo(params) {
for (let i = 0; i < 3; i++) {
console.log(i);
yield i; // 生产或产出i
}
}
console.log(foo());
---------------------------
Generator {_invoke: ƒ}
再来看,下面代码中.next()是固定的语法,输出的是一个对象,对象有两个属性,一个是value,一个是done。value代表当前值是什么,done表示Generator函数是否执行完。
// 一般function和*紧挨在一起
function* foo(params) {
for (let i = 0; i < 3; i++) {
// 生产或产出i
yield i;
}
}
// next()是固定的语法
let f = foo().next()
console.log(f);
-------------------------------
{value: 0, done: false}
再继续看,当调用next()后,会执行到yield后面的语句为止,再次调用时,会从当前yield语句之后执行
// 一般function和*紧挨在一起
function* foo(params) {
for (let i = 0; i < 3; i++) {
// console.log(i);
yield i;
}
}
// next()是固定的语法
let f = foo()
console.log(f.next());
console.log(f.next());
console.log(f.next());
console.log(f.next());
------------------------------------
{value: 0, done: false}
{value: 1, done: false}
{value: 2, done: false}
{value: undefined, done: true}
yield只能在Generator内部使用,不能在其它地方用,比如下面不能在其它函数里使用:
function gen(params) {
params.forEach(item => {
yield item
});
}
----------------------
Module build failed
来看一个复杂一点的例子:
next()可以传一个参数,这个参数表示的是Grenerator内部的上一条yield语句的返回值
function* gen(x) {
let y = 2 * (yield x + 1);
let z = yield y / 3;
return x + y + z;
}
let g = gen(5)
console.log(g.next()) // x + 1 = 6
// 这里没有传参,相当于传入的是undefined
console.log(g.next()) // 2 * undefined = NaN
console.log(g.next()) // NaN
----------------------------------
{value: 6, done: false}
{value: NaN, done: false}
{value: NaN, done: true}
现在把参数都传进去试一下:
function* gen(x) {
let y = 2 * (yield x + 1);
let z = yield y / 3;
return x + y + z;
}
let g = gen(5)
console.log(g.next())
console.log(g.next(12))
console.log(g.next(13))
// ------------------------------
{value: 6, done: false}
{value: 8, done: false}
{value: 42, done: true}
小例子7的倍数就暂定
function* count(x = 1) {
while (true) {
if( x % 7 === 0) {
yield x
}
x++
}
}
let n = count()
console.log(n.next().value)
console.log(n.next().value)
console.log(n.next().value)
console.log(n.next().value)
--------
7
14
21
28
再来看把之前Promise()里的三个异步请求改造到Grenerator函数中:
再次理解next(),next会执行到yield后面的表达式,这个不要忘记了
function ajax(url, callback) {
var xmlhttp;
// 1、创建XMLHttpRequest对象
// window.XMLHttpRequest这个对象存在,说明当前浏览器是IE7+或chrome
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
// 兼容早期浏览器
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// 2、发送请求
xmlhttp.open("GET", url, true);
xmlhttp.send();
// 3、接收服务端响应
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
var obj = JSON.parse(xmlhttp.responseText);
callback(obj)
}
};
}
var addUrl = "http://jsonplaceholder.typicode.com/users";
function request(url) {
ajax(url, res => {
getData.next(res);
})
}
function* gen() {
let res1 = yield request(addUrl)
console.log(res1)
let res2 = yield request(addUrl)
console.log(res2)
let res3 = yield request(addUrl)
console.log(res3);
}
let getData = gen()
getData.next();
--------------------------------------------------------------
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]