集合概念有字符串、数组、对象、Map、Set,需要有一个统一的接口机制来处理所有不同的数据结构。
是什么
迭代器iterator
是一种接口,为不同的数据结构提供统一的访问机制
好处
Iterator
接口(该接口的值为迭代器对象),就可以完成for..of
遍历操作使用场景
for-of
遍历,Array.from
创建浅拷贝数组(…)
也会调用默认的 Iterator 接口。Set
结构进行解构赋值时,会默认调用Symbol.iterator方法。迭代器对象
满足下属条件的对象可以称其为迭代器对象
next
方法,每次调用next
方法都将返回一个结果。结果值是一个object {value:xxx,done}
,value
表示具体的返回值, done
是布尔类型的,表示集合是否遍历完成。next
方法,指针都会向后移动一个位置。部署迭代器接口
[Symbol.iterator]
的属性,也称为实现了Iterator接口[Symbol.iterator]
的属性会返回一个函数createIterator
函数,创造迭代器对象的方法
next
的方法next
方法每次执行都会返回一个对象{value: value, done: boolean}
部署了迭代器接口的数据结构被称为可迭代对象
String,Array,TypedArray,Map 和 Set 都部署了迭代器接口,因为它们的原型对象都有一个[Symbol.iterator]
方法。
案例:创建一个迭代器对象
/*
给数据结构部署iterator接口
[Symbol.iterator] = createIterator
*/
// createIterator方法:创建一个迭代器对象
// 如果需要实现逆序:i初始化为items.length-1,依次i--
function createIterator(items) {
let i = 0; // 内部指针
//迭代器对象,它具有一个 next 方法,该方法会返回一个对象,包含 value 和 done 两个属性
return {
next: function () {
let done = i >= items.length;
let val = !done ? items[i++] : undefined;
return {
done: done,
value: val
}
}
}
}
//测试
var it = createIterator(['a', 'b', 'c']);
console.log(it.next());// {value: "a", done: false}
console.log(it.next());// {value: "b", done: false}
console.log(it.next());// {value: "c", done: false}
console.log(it.next());// "{ value: undefined, done: true }"
console.log(it.next());// "{ value: undefined, done: true }"
console.log(it.next());// "{ value: undefined, done: true }"
如果循环的是promise数组,promise的value是异步获取的,所以在当前位置是获取不到其value值。
部署异步迭代器接口
[Symbol.asyncIterator]
异步迭代器接口
function createIterator(items) {
let i = 0; // 内部指针
//迭代器对象,它具有一个 next 方法,该方法会返回一个对象,包含 value 和 done 两个属性
return {
next: function () {
let done = i >= items.length;
const value = done ? undefined : i++;
return Promise.resolve({ value, done });
}
}
}
同步迭代器
// 迭代器对象
interface Iterator {
next(value) : IteratorResult;
[optional] throw(value) : IteratorResult;
[optional] return(value) : IteratorResult;
}
// 迭代结果
interface IteratorResult {
value : any;
done : bool;
}
异步迭代器
// 异步迭代器
interface AsyncIterator {
next(value) : Promise<IteratorResult>;
[optional] throw(value) : Promise<IteratorResult>;
[optional] return(value) : Promise<IteratorResult>;
}
// 迭代结果
interface IteratorResult {
value : any;
done : bool;
}
for await of
循环可以暂停循环,当第一个异步执行完成后才会执行下一个,最后是让输出结果保持同步顺序输出。
对于promise数组来说,一般按顺序获取其结果使用Promise.all()
,这样每一次promise的结果只能从最后返回的数组中获取(前提是所有promise都成功)。
在实际开发中,假设每一个promise是一个请求,那么就在请求返回的地方进行一些操作。
那么如何循环顺序获取到promise
数组中的value
值?
// 模拟一些从后端请求获取的数据等
function Gen(time) {
return new Promise((resolve) => {
setTimeout(function () {
// 模拟每个任务执行时间不一样,任务执行的结果由resolve返回。
resolve(time);
}, time);
});
}
async function test() {
const arr = [Gen(2000), Gen(1000), Gen(3000)]; //
let i = 0;
for (const item of arr) {
console.log(
Date.now(),
await item, //这里的打印会放入微队列
);
}
}
test();
//1698219031697 2000
//1698219033701 1000
//1698219033701 3000
这种写法虽然可以得到结果,但是时间不太正确。如果把异步任务假想成一个后端请求,那么2000的结果出来的时候,1000早就执行完毕了。所以最终解决方案for-await-of
function Gen(time) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(time)
},time)
})
}
async function test() {
let arr = [Gen(2000), Gen(1000), Gen(3000)]
for await(let item of arr) {
console.log(Date.now(), item) //item直接是promise的value值
}
}
test()
//1698218308077 2000
//1698218308077 1000
//1698218309080 3000
//等价于
const p1 = await Gen[2000];
console.log(p1);
const p2 = await Gen[1000];
console.log(p2);
const p3 = await Gen[3000];
console.log(p3);