初次邂逅
- 迭代器:具备遍历的功能;
- 一般可迭代对象具有Symbol.iterator属性
- 可迭代(可被遍历)的内置对象:数组(
# Array.prototype[Symbol.iterator]())、字符串(String.prototype[Symbol.iterator]())等等;
let arr = [1,2,3]
for(let item of arr){
console.log(item)
}
let str = 'lxx'
for(let char of arr){
console.log(char)
}
- 自定义可遍历对象,具备Symbol.iterator属性
let obj = {
items: [6, 7, 8],
[Symbol.iterator]() {
let idx = 0;
let next = () => {
if (idx < this.items.length) {
return { value: this.items[idx++], done: false };
} else {
return { done: true };
}
};
return { next };
},
};
for (let item of obj) {
console.log(item);
}
- 生成器函数,有
*标识并且和关键字yield搭配使用,可用来控制函数的执行,可暂停函数的执行
function* gen() {
yield 1;
yield 2;
yield 3;
}
let it = gen()
console.log(it)
- 调用生成器函数生成迭代器对象,具有
next、return、throw等方法
- 调用一次
next方法,就会执行一个yield,有n个yield,则需要调用n + 1个next
- 每调用一次
next时,执行的代码内容(范围)是上边的代码到yield右侧(不包含左边的赋值)
let res1 = it.next();
console.log(res1);
let res2 = it.next();
console.log(res2);
let res3 = it.next();
console.log(res3);
let res4 = it.next();
console.log(res4);
- 除第一个调用的
next之外,后面调用时传递的参数,都会传(赋值)给相应位置的yield左侧的变量
function* gen() {
let r1 = yield 1;
console.log(r1);
let r2 = yield 2;
console.log(r2);
let r3 = yield 3;
console.log(r3);
}
let it = gen()
it.next('a');
it.next('b');
it.next('c');
it.next('d');
- 因为生成器函数的执行结果是个迭代器对象,所以可以使用
for...of进行遍历,得到的每一项是yield产生的值,有几个yield就会循环几项
for(let item of it){
console.log(item)
}
- 因为生成器函数中不确定有几个
yield(不确定有几个待执行的任务),但每执行完一个任务会知道是否所有任务已经完全执行完了,所以可以使用do...while来执行
let res;
do {
res = it.next();
console.log(res.value);
} while (!res.done);
function next() {
let { value, done } = it.next();
if (done) {
console.log(所有任务执行完毕");
} else {
console.log(value);
next(); // 继续向后执行
}
}
next();
function* gen() {
yield 1;
yield new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 2000);
});
yield 3;
}
let it = gen();
console.log(it);
for (let item of it) {
console.log(item);
}
- 可以借助自定义迭代方法,检测出产生值的类型,进行特殊处理
function next() {
let { value, done } = it.next();
if (done) {
console.log("函数执行完毕");
} else {
console.log(value);
if (value instanceof Promise) {
value.then((res) => {
console.log(res);
next();
});
} else {
next();
}
}
}
温故而知新
class PubSub {
constructor() {
this.events = {};
}
on(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName].push(callback);
} else {
this.events[eventName] = [callback];
}
}
emit(eventName) {
this.events[eventName].forEach((callback) => callback());
}
}
function* tasks(){
yield 111;
yield 222;
yield 333;
}
let it = tasks()
function next(){
let {value, done} = it.next()
if(done){
console.log('所有任务执行完毕')
}else{
console.log(value)
next()
}
}
next()
- 有异步任务,同样希望按顺序执行,执行完上一个任务,才会执行下一个任务
function* tasks() {
yield 111;
yield new Promise((resolve) => {
setTimeout(() => {
resolve(222);
}, 2000);
});
yield 333;
}
let it = tasks();
function next() {
let { value, done } = it.next();
if (done) {
console.log("所有任务执行完毕");
} else if (typeof value.then === "function") {
value.then((res) => {
console.log(res);
next();
});
} else {
console.log(value);
next();
}
}
next();
<button id="btn">btn</button>
<script>
btn.onclick = () => {
pubSub.emit("send");
};
class PubSub {
constructor() {
this.events = {};
}
on(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName].push(callback);
} else {
this.events[eventName] = [callback];
}
}
emit(eventName) {
this.events[eventName].forEach((callback) => callback());
}
}
let pubSub = new PubSub();
function* tasks() {
yield 111;
yield new Promise((resolve) => {
setTimeout(() => {
resolve(222);
}, 2000);
});
yield 333;
yield "pause";
yield 444;
}
let it = tasks();
function next() {
let { value, done } = it.next();
if (done) {
console.log("所有任务执行完毕");
} else if (value === "pause") {
pubSub.on("send", () => {
console.log("send事件触发了");
next();
});
} else if (typeof value.then === "function") {
value.then((res) => {
console.log(res);
next();
});
} else {
console.log(value);
next();
}
}
next();
</script>
- 嵌套的生成器函数,执行时,一层层进去,再一层层出来,最后执行完所有任务
function isCustomIterable(obj) {
if (typeof obj[Symbol.iterator] === "function" && typeof obj !== "string") {
const iterator = obj[Symbol.iterator]();
if (typeof iterator.next === "function") {
if (!Array.isArray(obj)) {
return true;
}
}
}
return false;
}
function* task2() {
yield "任务二开始";
yield new Promise((resolve) => {
setTimeout(() => {
resolve("任务三:异步任务");
}, 2000);
});
yield "任务二结束";
}
function* task1() {
yield "任务一开始";
yield task2();
yield "任务一结束";
}
function* tasks() {
yield "总任务开始";
yield task1();
yield "总任务结束";
}
function run(generator, cb) {
const it = typeof generator === "function" ? generator() : generator;
function myNext() {
const { value, done } = it.next();
if (done) {
console.log("当前任务所有步骤都完成");
cb && cb();
} else if (isCustomIterable(value)) {
run(value, myNext);
} else if (value instanceof Promise && typeof value.then === "function") {
value.then((res) => {
console.log(res);
myNext();
});
} else {
console.log(value);
myNext();
}
}
myNext();
}
run(tasks);
再见来不及挥手
- 迭代器对象具有可被遍历的特性
- 生成器函数可产生迭代器对象
- 生成器函数里面的代码可被控制执行
- 生成器函数中有
n个yield,那么需要调用n+1次next方法,生成器函数才会执行完