迭代器和生成器
WARNING
大量 code 警告
迭代器
背景知识
- 什么是迭代?
从一个数据集合中按照一定的顺序,不断取出数据的过程
- 迭代和遍历的区别?
迭代强调的是依次取数据,并不保证取多少,也不保证把所有的数据取完 遍历强调的是要把整个数据依次全部取出
- 迭代器
对迭代过程的封装,在不同的语言中有不同的表现形式,通常为对象
- 迭代模式
一种设计模式,用于统一迭代过程,并规范了迭代器规格:
- 迭代器应该具有得到下一个数据的能力
- 迭代器应该具有判断是否还有后续数据的能力
JS中的迭代器
JS规定,如果一个对象具有next方法,并且该方法返回一个对象,该对象的格式如下:
{value: 值, done: 是否迭代完成}
{value: 值, done: 是否迭代完成}
模板
const obj = {
next() {
return {
value:xxx,
done:xx
}
}
}
const obj = {
next() {
return {
value:xxx,
done:xx
}
}
}
则认为该对象obj是一个迭代器 含义:
- next方法:用于得到下一个数据
- 返回的对象
- value:下一个数据的值
- done:boolean,是否迭代完成
演示1
const arr = [1, 2, 3, 4, 5];
//迭代数组arr
const iterator = {
i: 0, //当前的数组下标
next() {
var result = {
value: arr[this.i],
done: this.i >= arr.length//下标越界了
}
this.i++;
return result;
}
}
//让迭代器不断的取出下一个数据,直到没有数据为止
let data = iterator.next();
while (!data.done) { //只要没有迭代完成,则取出数据
console.log(data.value)
//进行下一次迭代
data = iterator.next();
}
console.log("迭代完成")
const arr = [1, 2, 3, 4, 5];
//迭代数组arr
const iterator = {
i: 0, //当前的数组下标
next() {
var result = {
value: arr[this.i],
done: this.i >= arr.length//下标越界了
}
this.i++;
return result;
}
}
//让迭代器不断的取出下一个数据,直到没有数据为止
let data = iterator.next();
while (!data.done) { //只要没有迭代完成,则取出数据
console.log(data.value)
//进行下一次迭代
data = iterator.next();
}
console.log("迭代完成")
演示2
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];
// 迭代器创建函数 iterator creator
function createIterator(arr) {
let i = 0;//当前的数组下标
return {
next() {
var result = {
value: arr[i],
done: i >= arr.length
}
i++;
return result;
}
}
}
const iter1 = createIterator(arr1);
iter1.next()
const iter2 = createIterator(arr2);
iter2.next()
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];
// 迭代器创建函数 iterator creator
function createIterator(arr) {
let i = 0;//当前的数组下标
return {
next() {
var result = {
value: arr[i],
done: i >= arr.length
}
i++;
return result;
}
}
}
const iter1 = createIterator(arr1);
iter1.next()
const iter2 = createIterator(arr2);
iter2.next()
演示3:无限延伸功能
// 依次得到斐波拉契数列前面n位的值
// 1 1 2 3 5 8 13 .....
//创建一个斐波拉契数列的迭代器
function createFeiboIterator() {
let prev1 = 1,
prev2 = 1, //当前位置的前1位和前2位
n = 1; //当前是第几位
return {
next() {
let value;
if (n <= 2) {
value = 1;
} else {
value = prev1 + prev2;
}
const result = {
value,
done: false//这个数列无限延伸
};
prev2 = prev1;
prev1 = result.value;
n++;
return result;
}
}
}
const iterator = createFeiboIterator();
iterator.next()
// 依次得到斐波拉契数列前面n位的值
// 1 1 2 3 5 8 13 .....
//创建一个斐波拉契数列的迭代器
function createFeiboIterator() {
let prev1 = 1,
prev2 = 1, //当前位置的前1位和前2位
n = 1; //当前是第几位
return {
next() {
let value;
if (n <= 2) {
value = 1;
} else {
value = prev1 + prev2;
}
const result = {
value,
done: false//这个数列无限延伸
};
prev2 = prev1;
prev1 = result.value;
n++;
return result;
}
}
}
const iterator = createFeiboIterator();
iterator.next()
可迭代协议与for-of循环
可迭代协议
- 迭代器(iterator):一个具有next方法的对象,next方法返回下一个数据并且能指示是否迭代完成
- 迭代器创建函数(iterator creator):一个返回迭代器的函数
可迭代协议
ES6规定,如果一个对象具有知名符号属性Symbol.iterator
,并且属性值是一个迭代器创建函数,则该对象是可迭代的(iterable) 数组就是个可迭代对象
思考:如何知晓一个对象是否是可迭代的?答案:数组、类数组、自己写的对象都可以做成可迭代对象
思考:如何遍历一个可迭代对象?答案:for-of循环
for-of 循环
for-of 循环用于遍历可迭代对象,格式如下
//迭代完成后循环结束
for(const item in iterable){
//iterable:可迭代对象
//item:每次迭代得到的数据
}
//迭代完成后循环结束
for(const item in iterable){
//iterable:可迭代对象
//item:每次迭代得到的数据
}
for-of循环的原理
调用对象的[Symbol.iterator]方法,得到一个迭代器。不断调用next方法,只有返回的done为false,则将返回的value传递给变量,然后进入循环体执行一次。
演示:数组就是个可迭代对象
const arr = [5, 7, 2, 3, 6];
// const iterator = arr[Symbol.iterator]();
// let result = iterator.next();
// while (!result.done) {
// const item = result.value; //取出数据
// console.log(item);
// //下一次迭代
// result = iterator.next();
// }
// 等价于
for (const item of arr) {
console.log(item)
}
const arr = [5, 7, 2, 3, 6];
// const iterator = arr[Symbol.iterator]();
// let result = iterator.next();
// while (!result.done) {
// const item = result.value; //取出数据
// console.log(item);
// //下一次迭代
// result = iterator.next();
// }
// 等价于
for (const item of arr) {
console.log(item)
}
演示3
<div>1</div>
<div>2</div>
<div>3</div>
<script>
const divs = document.querySelectorAll("div");
// const iterator = divs[Symbol.iterator]()
// let result = iterator.next();
// while (!result.done) {
// const item = result.value; //取出数据
// console.log(item);
// //下一次迭代
// result = iterator.next();
// }
// 等价于
for (const item of divs) {
console.log(item);
}
</script>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
const divs = document.querySelectorAll("div");
// const iterator = divs[Symbol.iterator]()
// let result = iterator.next();
// while (!result.done) {
// const item = result.value; //取出数据
// console.log(item);
// //下一次迭代
// result = iterator.next();
// }
// 等价于
for (const item of divs) {
console.log(item);
}
</script>
演示:自定义可迭代对象
//可迭代对象
var obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this);//得到对象this里面所有属性名的一个数组
// console.log(keys)
let i = 0;
return {
next: () => {
const propName = keys[i];
const propValue = this[propName];
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
for (const item of obj) {
console.log(item); // {propName:"a", propValue:1}
}
//可迭代对象
var obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this);//得到对象this里面所有属性名的一个数组
// console.log(keys)
let i = 0;
return {
next: () => {
const propName = keys[i];
const propValue = this[propName];
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
for (const item of obj) {
console.log(item); // {propName:"a", propValue:1}
}
展开运算符与可迭代对象
展开运算符可以作用于可迭代对象,这样,就可以轻松的将可迭代对象转换为数组。 演示
var obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this);
let i = 0;
return {
next: () => {
const propName = keys[i];
const propValue = this[propName];
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
const arr = [...obj];
console.log(arr);
function test(a, b) {
console.log(a, b)
}
test(...obj);
var obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this);
let i = 0;
return {
next: () => {
const propName = keys[i];
const propValue = this[propName];
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result;
}
}
}
}
const arr = [...obj];
console.log(arr);
function test(a, b) {
console.log(a, b)
}
test(...obj);
迭代器和可迭代协议,解决实际问题
解决副作用的 redux 中间件
redux-thunk:需要改动action,可接收action是一个函数
redux-promise:需要改动action,可接收action是一个promise对象,或action的payload是一个promise对象
以上两个中间件,会导致action或action创建函数不再纯净。
- redux-saga将解决这样的问题,它不仅可以保持action、action创建函数、reducer的纯净,而且可以用模块化的方式解决副作用,并且功能非常强大。
redux-saga是建立在ES6的生成器基础上的,要熟练的使用saga,必须理解生成器。
要理解生成器,必须先理解迭代器和可迭代协议。
生成器
生成器 (Generator)
- 什么是生成器?
生成器是一个通过构造函数Generator创建的对象,生成器既是一个迭代器(有next方法),同时又是一个可迭代对象(有知名符号),可以用于for of循环
//伪代码
var generator = new Generator();
generator.next();//它具有next方法
var iterator = generator[Symbol.iterator];//它也是一个可迭代对象
for(const item of generator){
//由于它是一个可迭代对象,因此也可以使用for of循环
}
//伪代码
var generator = new Generator();
generator.next();//它具有next方法
var iterator = generator[Symbol.iterator];//它也是一个可迭代对象
for(const item of generator){
//由于它是一个可迭代对象,因此也可以使用for of循环
}
注意:Generator构造函数,不提供给开发者使用,仅作为JS引擎内部使用
- 如何创建生成器
生成器的创建,必须使用生成器函数(Generator Function)
- 如何书写一个生成器函数呢?
//这是一个生成器函数,该函数一定返回一个生成器
function* method(){
}
//这是一个生成器函数,该函数一定返回一个生成器
function* method(){
}
- 生成器函数内部是如何执行的?
第一次调用只是生成了生成器,并没有调用里面 生成器函数内部是为了给生成器的每次迭代提供的数据 每次调用生成器的next方法,将导致生成器函数运行到下一个yield关键字位置 yield是一个关键字,该关键字只能在生成器函数内部使用,表达“产生”一个迭代数据。
- 有哪些需要注意的细节?
1). 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中 2). 调用生成器的next方法时,可以传递参数,传递的参数会交给yield表达式的返回值 3). 第一次调用next方法时,传参没有任何意义 4). 在生成器函数内部,可以调用其他生成器函数,但是要注意加上*号
- 生成器的其他API
- return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束
generator.return()//结束了,done为true
generator.return(3)//value=3
generator.return()//结束了,done为true
generator.return(3)//value=3
- throw方法:调用该方法,可以在生成器中产生一个错误
generator.throw(new Error("sdbjjas"))
generator.throw(new Error("sdbjjas"))
演示
function* test() {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const generator = test();
function* test() {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行")
}
const generator = test();
优化演示:数组的迭代
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];
// 迭代器创建函数 iterator creator
function* createIterator(arr) {
for (const item of arr) {
yield item;
}
}
const iter1 = createIterator(arr1);
const iter2 = createIterator(arr2);
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];
// 迭代器创建函数 iterator creator
function* createIterator(arr) {
for (const item of arr) {
yield item;
}
}
const iter1 = createIterator(arr1);
const iter2 = createIterator(arr2);
创建一个斐波拉契数列的迭代器
function* createFeiboIterator() {
let prev1 = 1,
prev2 = 1, //当前位置的前1位和前2位
n = 1; //当前是第几位
while (true) {
if (n <= 2) {
yield 1;
} else {
const newValue = prev1 + prev2
yield newValue;
prev2 = prev1;
prev1 = newValue;
}
n++;
}
}
const iterator = createFeiboIterator();
function* createFeiboIterator() {
let prev1 = 1,
prev2 = 1, //当前位置的前1位和前2位
n = 1; //当前是第几位
while (true) {
if (n <= 2) {
yield 1;
} else {
const newValue = prev1 + prev2
yield newValue;
prev2 = prev1;
prev1 = newValue;
}
n++;
}
}
const iterator = createFeiboIterator();
演示:生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中
function* test() {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行");
return 10;
}
const generator = test();
function* test() {
console.log("第1次运行")
yield 1;
console.log("第2次运行")
yield 2;
console.log("第3次运行");
return 10;
}
const generator = test();
演示:调用生成器的next方法时,可以传递参数,传递的参数会交给yield表达式的返回值
function* test() {
console.log("函数开始")
let info = yield 1;//这里info不是1,这里根据参数动态变化
console.log(info)
info = yield 2 + info;
console.log(info)
}
const generator = test();
控制台
generator.next()
demo.js:2 函数开始
{value: 1, done: false}
generator.next(5)
{value: 7, done: false}
function* test() {
console.log("函数开始")
let info = yield 1;//这里info不是1,这里根据参数动态变化
console.log(info)
info = yield 2 + info;
console.log(info)
}
const generator = test();
控制台
generator.next()
demo.js:2 函数开始
{value: 1, done: false}
generator.next(5)
{value: 7, done: false}
演示:在生成器函数内部,可以调用其他生成器函数,但是要注意加上*号
function* t1(){
yield "a"
yield "b"
}
function* test() {
两种错误的调用方式:
1. t1()// 调用生成器函数不会导致里面的代码执行
2. yield t1();// 将生成器对象给了yield执行
yield* t1();//相当于把t1里面代码直接copy过来了
yield 1;
yield 2;
yield 3;
}
const generator = test();
function* t1(){
yield "a"
yield "b"
}
function* test() {
两种错误的调用方式:
1. t1()// 调用生成器函数不会导致里面的代码执行
2. yield t1();// 将生成器对象给了yield执行
yield* t1();//相当于把t1里面代码直接copy过来了
yield 1;
yield 2;
yield 3;
}
const generator = test();
生成器
// generator.next === generator[Symbol.iterator]().next()
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
// generator.next === generator[Symbol.iterator]().next()
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* createArrayIterator(arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
console.log(`第${i}次迭代`);
yield item;
}
console.log("函数结束");//迭代完成后运行
}
var generator = createArrayIterator([1, 2, 3, 4, 5, 6]);
function* createArrayIterator(arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
console.log(`第${i}次迭代`);
yield item;
}
console.log("函数结束");//迭代完成后运行
}
var generator = createArrayIterator([1, 2, 3, 4, 5, 6]);
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
return;// 后面不会运行了
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
return;// 后面不会运行了
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function asyncGetData() {
return new Promise(resolve => {
setTimeout(() => {
resolve("成哥")
}, 2000);
})
}
function* task() {
console.log("开始获取数据....");
const data = yield asyncGetData()
console.log("获取到数据:", data);
const data2 = yield asyncGetData();
console.log("又获取到了数据:", data2);
const data3 = yield 1;
console.log("又获取到了数据:", data3)
}
/**
* 通用函数:运行一个生成器任务
*/
function run(generatorFunction) {
const generator = generatorFunction(); //得到一个生成器
next();
/**
* 封装了generator的next方法,进行下一次迭代
*/
function next(nextValue) {
const result = generator.next(nextValue);
if (result.done) {
//迭代结束了
return;
}
const value = result.value; //拿到迭代的数据
if (typeof value.then === "function") {
//迭代的数据是一个Promise
value.then(data => next(data));
} else {
next(result.value);
}
}
}
run(task);
function asyncGetData() {
return new Promise(resolve => {
setTimeout(() => {
resolve("成哥")
}, 2000);
})
}
function* task() {
console.log("开始获取数据....");
const data = yield asyncGetData()
console.log("获取到数据:", data);
const data2 = yield asyncGetData();
console.log("又获取到了数据:", data2);
const data3 = yield 1;
console.log("又获取到了数据:", data3)
}
/**
* 通用函数:运行一个生成器任务
*/
function run(generatorFunction) {
const generator = generatorFunction(); //得到一个生成器
next();
/**
* 封装了generator的next方法,进行下一次迭代
*/
function next(nextValue) {
const result = generator.next(nextValue);
if (result.done) {
//迭代结束了
return;
}
const value = result.value; //拿到迭代的数据
if (typeof value.then === "function") {
//迭代的数据是一个Promise
value.then(data => next(data));
} else {
next(result.value);
}
}
}
run(task);
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值,还没有完成赋值 绝不是把1赋值给result,result是外部给他的
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
var result = generator.next(); //{value:1, done:false}
while (!result.done) {
//有迭代的值
result = generator.next(result.value);//如果想把yield返回的值交给result
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值,还没有完成赋值 绝不是把1赋值给result,result是外部给他的
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
var result = generator.next(); //{value:1, done:false}
while (!result.done) {
//有迭代的值
result = generator.next(result.value);//如果想把yield返回的值交给result
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
try {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值.
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
} catch (err) {
console.log("报错了");
yield "Abc";
}
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
try {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值.
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
} catch (err) {
console.log("报错了");
yield "Abc";
}
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* g2() {
console.log("g2-开始");
let result = yield "g1";
console.log("g2-运行1");
result = yield "g2";
return 123;
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
result = yield* g2(); //result为g2函数的返回值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* g2() {
console.log("g2-开始");
let result = yield "g1";
console.log("g2-运行1");
result = yield "g2";
return 123;
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
result = yield* g2(); //result为g2函数的返回值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
生成器函数特点
- 调用生成器函数,会返回一个生成器,而不是执行函数体(因为,生成器函数的函数体执行,收到生成器控制)
- 每当调用了生成器的next方法,生成器的函数体会从上一次yield的位置(或开始位置)运行到下一个yield
- yield关键字只能在生成器内部使用,不可以在普通函数内部使用
- 它表示暂停,并返回一个当前迭代的数据
- 如果没有下一个yield,到了函数结束,则生成器的next方法得到的结果中的done为true
- yield关键字后面的表达式返回的数据,会作为当前迭代的数据
- 生成器函数的返回值,会作为迭代结束时的value
- 但是,如果在结束过后,仍然反复调用next,则value为undefined
- 生成器调用next的时候,可以传递参数,该参数会作为生成器函数体上一次yield表达式的值。
- 生成器第一次调用next函数时,传递参数没有任何意义
- 生成器带有一个throw方法,该方法与next的效果相同,唯一的区别在于:
- next方法传递的参数会被返回成一个正常值
- throw方法传递的参数是一个错误对象,会导致生成器函数内部发生一个错误。
- 生成器带有一个return方法,该方法会直接结束生成器函数
- 若需要在生成器内部调用其他生成器,注意:如果直接调用,得到的是一个生成器,如果加入*号调用,则进入其生成器内部执行。如果是
yield* 函数()
调用生成器函数,则该函数的返回结果,为该表达式的结果
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* createArrayIterator(arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
console.log(`第${i}次迭代`)
yield item;
}
console.log("函数结束")
}
var generator = createArrayIterator([1, 2, 3, 4, 5, 6])
function* createArrayIterator(arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
console.log(`第${i}次迭代`)
yield item;
}
console.log("函数结束")
}
var generator = createArrayIterator([1, 2, 3, 4, 5, 6])
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
return;
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
yield 1; // {value:1, done:false}
return;
console.log("生成器函数的函数体 - 运行1");
yield 2;
console.log("生成器函数的函数体 - 运行2");
yield 3;
console.log("生成器函数的函数体 - 运行3");
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
var result = generator.next(); //{value:1, done:false}
while (!result.done) {
//有迭代的值
result = generator.next(result.value);
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
var result = generator.next(); //{value:1, done:false}
while (!result.done) {
//有迭代的值
result = generator.next(result.value);
}
function asyncGetData() {
return new Promise(resolve => {
setTimeout(() => {
resolve("成哥")
}, 2000);
})
}
function* task() {
console.log("开始获取数据....");
const data = yield asyncGetData()
console.log("获取到数据:", data);
const data2 = yield asyncGetData();
console.log("又获取到了数据:", data2);
const data3 = yield 1;
console.log("又获取到了数据:", data3)
}
/**
* 通用函数:运行一个生成器任务
*/
function run(generatorFunction) {
const generator = generatorFunction(); //得到一个生成器
next();
/**
* 封装了generator的next方法,进行下一次迭代
*/
function next(nextValue) {
const result = generator.next(nextValue);
if (result.done) {
//迭代结束了
return;
}
const value = result.value; //拿到迭代的数据
if (typeof value.then === "function") {
//迭代的数据是一个Promise
value.then(data => next(data));
} else {
next(result.value);
}
}
}
run(task);
function asyncGetData() {
return new Promise(resolve => {
setTimeout(() => {
resolve("成哥")
}, 2000);
})
}
function* task() {
console.log("开始获取数据....");
const data = yield asyncGetData()
console.log("获取到数据:", data);
const data2 = yield asyncGetData();
console.log("又获取到了数据:", data2);
const data3 = yield 1;
console.log("又获取到了数据:", data3)
}
/**
* 通用函数:运行一个生成器任务
*/
function run(generatorFunction) {
const generator = generatorFunction(); //得到一个生成器
next();
/**
* 封装了generator的next方法,进行下一次迭代
*/
function next(nextValue) {
const result = generator.next(nextValue);
if (result.done) {
//迭代结束了
return;
}
const value = result.value; //拿到迭代的数据
if (typeof value.then === "function") {
//迭代的数据是一个Promise
value.then(data => next(data));
} else {
next(result.value);
}
}
}
run(task);
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
try {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
} catch (err) {
console.log("报错了");
yield "Abc";
}
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
try {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
} catch (err) {
console.log("报错了");
yield "Abc";
}
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* g2() {
console.log("g2-开始");
let result = yield "g1";
console.log("g2-运行1");
result = yield "g2";
return 123;
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
result = yield* g2(); //result为g2函数的返回值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
function* g2() {
console.log("g2-开始");
let result = yield "g1";
console.log("g2-运行1");
result = yield "g2";
return 123;
}
//下面的函数是一个生成器函数,用于创建生成器
function* createGenerator() {
console.log("生成器函数的函数体 - 开始");
let result = yield 1; //将1作为第一次的迭代的值
result = yield* g2(); //result为g2函数的返回值
console.log("生成器函数的函数体 - 运行1", result);
result = yield 2; //将2作为第二次迭代的值
console.log("生成器函数的函数体 - 运行2", result);
result = yield 3;
console.log("生成器函数的函数体 - 运行3", result);
return "结束";
}
var generator = createGenerator(); //调用后,一定得到一个生成器
生成器应用-异步任务控制
高仿await
function* task() {
const d = yield 1;
console.log(d)
// //d : 1
const resp = yield fetch("http://101.132.72.36:5100/api/local")
const result = yield resp.json();
console.log(result);
}
run(task)
function run(generatorFunc) {
const generator = generatorFunc();
let result = generator.next(); //启动任务(开始迭代), 得到迭代数据
handleResult();
//对result进行处理
function handleResult() {
if (result.done) {
return; //迭代完成,不处理
}
//迭代没有完成,分为两种情况
//1. 迭代的数据是一个Promise
//2. 迭代的数据是其他数据
if (typeof result.value.then === "function") {//promise里面有个then方法
//1. 迭代的数据是一个Promise
//等待Promise完成后,再进行下一次迭代
result.value.then(data => {
result = generator.next(data)
handleResult();
})
} else {
//2. 迭代的数据是其他数据,直接进行下一次迭代
result = generator.next(result.value)
handleResult();
}
}
}
function* task() {
const d = yield 1;
console.log(d)
// //d : 1
const resp = yield fetch("http://101.132.72.36:5100/api/local")
const result = yield resp.json();
console.log(result);
}
run(task)
function run(generatorFunc) {
const generator = generatorFunc();
let result = generator.next(); //启动任务(开始迭代), 得到迭代数据
handleResult();
//对result进行处理
function handleResult() {
if (result.done) {
return; //迭代完成,不处理
}
//迭代没有完成,分为两种情况
//1. 迭代的数据是一个Promise
//2. 迭代的数据是其他数据
if (typeof result.value.then === "function") {//promise里面有个then方法
//1. 迭代的数据是一个Promise
//等待Promise完成后,再进行下一次迭代
result.value.then(data => {
result = generator.next(data)
handleResult();
})
} else {
//2. 迭代的数据是其他数据,直接进行下一次迭代
result = generator.next(result.value)
handleResult();
}
}
}