所谓的迭代,用过es6的兄弟肯定已经接触过了,比如arr是一个数组,**[…arr]**还有for of 循环都是的。我说一说他背后的东西。
同步迭代
The interfaces for sync iteration ,借助typescript来写:
interface Iterable {
[Symbol.iterator]() : Iterator;
}
interface Iterator {
next() : IteratorResult;
}
interface IteratorResult {
value : any;
done : boolean;
}
总之,可迭代的对象(Iterable)上面有个[Symbol.iterator]方法,这个方法返回一个迭代器(Iterator),这个Iterator上面有个next方法,next方法调用的时候返回IteratorResult,IteratorResult的格式是::{ value:any, done:boolen }。。。那么,我们自己动手实现一个可迭代的对象:
方法1
const tongbuObj1 = {
arr: [1, 2, 3],
[Symbol.iterator]() {
let length = this.arr.length;
let index = 0;
let it = {
next: () => {
return {
done: index >= length,
value: this.arr[index++]
}
}
};
return it;
}
};
tongbuObj1上面由个arr, 我希望达到的目的是[…tongbuObj1]能和[…tongbuObj1.arr]一样,怎么做呢,就是实现[Symbol.iterator]方法就行了。
方法2
其实上面的方法可以再次化简,因为我们的要求是对象上有[Symbol.iterator]方法,并且这个方法返回一个对象,返回的对象上面有个next方法,那么下面这样是不是更简洁:
const tongbuObj2 = {
arr: [1, 2, 3],
index: 0,
[Symbol.iterator]() {
return this;
},
next() {
return {
done: this.index >= this.arr.length,
value: this.arr[this.index++]
}
}
};
方法3
也许看到next的时候兄弟们已经想到了,这东西和es6里面生成器有点类似,其实就是这样,es6里面的生成器默认实现了可迭代接口,所以上面的例子还可以再次优化:
const tongbuObj3 = {
arr: [1, 2, 3],
* [Symbol.iterator]() {
for (let i = 0; i < this.arr.length; i++) {
yield this.arr[i];
}
}
};
方法1方法2方法3调用之后都是:
console.log([...tongbuObj1]);
console.log([...tongbuObj2]);
console.log([...tongbuObj3]);
// 结果是:
[ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 1, 2, 3 ]
异步迭代
The interfaces for async iteration,借助typescript来写:
interface AsyncIterable {
[Symbol.asyncIterator]() : AsyncIterator;
}
interface AsyncIterator {
next() : Promise<IteratorResult>;
}
interface IteratorResult {
value: any;
done: boolean;
}
直接写一个例子,比较同步迭代和异步迭代吧,上代码:
// 先是同步迭代
const Async = 1;
const Bsync = 2;
function* gensync() {
yield Async;
yield Bsync;
}
async function fsync() {
for (let v of gensync()) { // 1
console.log('fsync', v);
}
}
fsync();
// 下面是异步迭代
const aasync = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 111);
});
const basync = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 1113);
});
function* genasync() {
yield aasync;
yield basync;
}
async function fasync() {
for await (let v of genasync()) { // 2
console.log('fasync', v);
}
}
fasync();
上面的代码输出:
fsync 1
fsync 2
fasync 1
fasync 3
总结:
同步迭代和异步迭代的区别,就在于next方法返回的是Promise还是普通值。甚至可以意会成2处的await是在等待v
参考文献:
https://exploringjs.com/es2018-es2019/ch_asynchronous-iteration.html