github地址
这是一个能在
Map
和Set
使用数组方法(如:map()
、filter()
,reduce()
)。而且如果使用多个操作符时,能只迭代一次,而不是补个操作符迭代一次。大大加快运行速度,对于运行一个很大的Set会有明显的效果。
这个包应用了ES6的Iterator的概念。默认可遍历的数据结构是具有Symbol.iterator
的属性。通过运行next方法就可以获得如下对象
{value:值, done: 是否到最后};
包用法:
iterate(uris)
.filter(uri => uri.startsWith('file://'))
.map(uri => uri.substr('file:///'.length))
.toSet()
简单说,toSet()
之前都是在不停装饰实例,成为一个新的遍历器。之后才开始迭代。
iterate(uris)
上面逻辑是:
function iterate(collection: Iterator | Iterable): IteratorWithOperators {
return new IteratorWithOperators(toIterator(collection))
}
就是用被传入对象的遍历器生成一个新的可遍历对象。
export class IteratorWithOperators implements IterableIterator {
/**
* @param source Iterator to wrap
*/
constructor(private source: Iterator) {}
/**
* Returns a `{ value, done }` object that adheres to the Iterator protocol
*/
next(): IteratorResult {
return this.source.next()
}
/**
* The presence of this method makes the Iterator itself Iterable.
* This makes it possible to pass it to `for of` and Iterable-accepting functions like `Array.from()`
*/
[Symbol.iterator](): this {
return this
}
/**
* Returns a new Iterator by running each element thru iteratee
*/
map(iteratee: (value: T) => R): IteratorWithOperators {
return new IteratorWithOperators(new MapIterator(this.source, iteratee))
}
....
能看出其实现了[Symbol.iterator]的方法,所以是可遍历的。
我们看下map操作的实现就明白为何会只迭代一次。直接看
new MapIterator(this.source, iteratee)
export class MapIterator implements Iterator {
constructor(private source: Iterator, private iteratee: (value: T) => R) {}
next(): IteratorResult {
const { value, done } = this.source.next()
return { value: !done && this.iteratee(value), done } as IteratorResult
}
}
可以看出,实例生成时,支撑保存了遍历器与处理方法。
所以当最后调用IteratorWithOperators
的非操作符的遍历方法时,会自动去调用遍历器的next
方法,从最底层开始,一层一层的往上调用操作符的逻辑,所以最底层遍历结束,整体也进入最后结束轮,仅需遍历一次。
PS: 也可以看出所有逻辑都是同步的。其实使用RxJS
也是可以只遍历一次,如:
of([1,2,3,4]).pipe(tap(....),map(...),mergeMap(....)).subscribe(cb)
但这个包可以让我们类似用原生的方法去操作,比较亲切。
如果觉得文章对你有点用的话,麻烦拿出手机,这里有一个你我都有的小福利(每天一次): 打开支付宝首页搜索“8601304”,即可领红包。谢谢支持