初次邂逅
- 迭代器:具备遍历的功能;
- 一般可迭代对象具有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 };
},
};
// 遍历对象时会调用自动调用Symbol.iterator方法
for (let item of obj) {
console.log(item);
}
- 生成器函数,有
*
标识并且和关键字yield
搭配使用,可用来控制函数的执行,可暂停函数的执行
// 相当于gen函数中有三个待执行的任务,希望挨个进行执行处理
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); // {value: 1, done: false}, value相当于是yield产生的值,done代表是否已经迭代完
let res2 = it.next();
console.log(res2); // {value: 2, done: false}
let res3 = it.next();
console.log(res3); // {value: 3, done: false}
let res4 = it.next();
console.log(res4); // {value: 3, done: false}
- 除第一个调用的
next
之外,后面调用时传递的参数,都会传(赋值)给相应位置的yield
左侧的变量
function* gen() {
let r1 = yield 1;
console.log(r1); // b
let r2 = yield 2;
console.log(r2); // c
let r3 = yield 3;
console.log(r3); // d
}
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(); // {value: 1, done: false}
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); // 拥有next方法,控制函数的执行
for (let item of it) {
console.log(item); // 迭代(遍历)迭代器对象产生:1,promise,3
}
- 可以借助自定义迭代方法,检测出产生值的类型,进行特殊处理
function next() {
let { value, done } = it.next();
if (done) {
console.log("函数执行完毕");
} else {
console.log(value);
if (value instanceof Promise) {
// 如果值是一个promise,就调用then方法
value.then((res) => {
console.log(res);
next(); // 处理完promise后再继续执行后续任务
});
} else {
next(); // 产生的普通值,就直接进行后续的任务
}
}
}
温故而知新
class PubSub {
constructor() {
// 存储不同类型的任务(事件)
// 数据格式:{event1: [fn1, fn2, ...], event2: [cb1, cb2, ...]}
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; // 任务一,最终产生的结果为111
yield 222; // 任务二,最终产生的结果为222
yield 333; // 任务三,最终产生的结果为333
}
// 调用生成器函数,获取迭代器对象
let it = tasks()
// 自定义遍历迭代对象的方法
function next(){
// 调用next方法获取一个任务的结果value,及是否所有任务执行完的标识done
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") {
// 是一个promise任务,等待执行完异步任务后,再继续向下执行其他任务
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") {
// 遇到pause标识时,先订阅一个事件,不继续往下执行任务
pubSub.on("send", () => {
console.log("send事件触发了");
next(); // 当该订阅的事件被执行了,则继续往下执行任务
});
} else if (typeof value.then === "function") {
// 是一个promise任务,等待执行完异步任务后,再继续向下执行其他任务
value.then((res) => {
console.log(res);
next();
});
} else {
console.log(value);
next();
}
}
next();
</script>
- 嵌套的生成器函数,执行时,一层层进去,再一层层出来,最后执行完所有任务
function isCustomIterable(obj) {
// 检查对象是否有[Symbol.iterator]方法,且不能是字符串
if (typeof obj[Symbol.iterator] === "function" && typeof obj !== "string") {
// 获取迭代器
const iterator = obj[Symbol.iterator]();
// 检查迭代器是否有next方法
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 "总任务结束";
}
// 入口函数,执行生成器函数(generator)的函数(run)
function run(generator, cb) {
const it = typeof generator === "function" ? generator() : generator; // 执行生成器函数,获取迭代器对象
// 自定义挨个执行任务的函数,作用就是挨个执行任务,每个任务就是一个生成器函数,每个生成器函数可以生成一个迭代器对象
// 每执行一次run方法,就会产生一个myNext方法
function myNext() {
const { value, done } = it.next(); // 执行next方法获取一个任务的结果value,及是否所有任务都完成的标识done
if (done) {
console.log("当前任务所有步骤都完成");
cb && cb(); // 每个生成器函数中有n个yield,那么需要执行n+1次next,该生成器函数才能执行完(即该函数才能执行完)
} else if (isCustomIterable(value)) {
// 自定义迭代器对象
// console.log(`结果的数据类型,${typeof value},结果(自定义迭代器值):${value}`);
run(value, myNext); // 递归调用,执行生成器函数
} else if (value instanceof Promise && typeof value.then === "function") {
value.then((res) => {
console.log(res);
myNext();
});
} else {
// 非自定义迭代器对象
// console.log(`结果的数据类型:${typeof value},结果(普通值):${value}`);
console.log(value);
myNext();
}
}
myNext();
}
run(tasks);
再见来不及挥手
- 迭代器对象具有可被遍历的特性
- 生成器函数可产生迭代器对象
- 生成器函数里面的代码可被控制执行
- 生成器函数中有
n
个yield
,那么需要调用n+1
次next
方法,生成器函数才会执行完