当前,像 LanguageService.getReferencesAtPosition()
或 getNavigateToItems()
这样的功能返回一个数组。这意味着,它们必须在返回之前收集所有引用/导航项,并阻塞CPU,直到那时。
如果你在像 angular/angular 这样的仓库中调用这样的函数,返回的数组可以很容易地有5万个元素,函数可能需要很长时间才能返回。这意味着UI只能显示结果,直到所有项目都被聚合(当然,你可以传递一个限制,但在 getNavigateToItems()
的情况下,可能会导致你想要找到的相关项没有被找到,因为匹配是模糊完成的,当 limit
项模糊匹配查询时,函数会提前返回)。例如,在 angular/angular 中,对 Http 的查询加上限制将返回很多不相关的 http
变量,但不带限制的查询将返回 Http
类)。如果你必须对最终得到的项目进行更多的过滤、转换等操作,那么就会产生不必要的额外迭代。
我建议添加或更改API以返回一个 Iterable
。这可以通过生成器实现。这将允许消费者从迭代器中“拉取”项目。
这意味着:
- 结果(如引用、符号)可以在源中找到后立即流式传输并显示在UI上
- 请求可以很容易地通过中止迭代(如
break
在for of
中)来取消 - 不再需要限制参数,只需在达到限制后中止迭代即可
- 如果需要对结果执行过滤、转换等操作,可以在同一个迭代“管道”中进行
不需要依赖项来使此工作正常运行,一切都在语言中。
返回的 Iterable 可以以多种方式消费,使用 for of
、生成器委托、迭代库或 Observables,或者轻松地转换为数组 with Array.from()
。
这个API可以通过添加一个新的变体并将旧的更改为委托和转换为数组的方式向后兼容地添加:
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
return Array.from(this.getReferencesIterableAtPosition(fileName, position);
}
getReferencesIterableAtPosition(fileName: string, position: number): IterableIterator<ReferenceEntry> {
// ...
}
1条答案
按热度按时间5m1hhzi41#
这似乎是个好建议。我们愿意添加一个新的API(出于向后兼容的目的,我们不能更改现有的API)。
需要注意的一点是,大多数LS的用户都在tsserver上,这是我们建议继续前进的方向。考虑到服务器协议的工作方式,这种改变不会带来太大的好处。
对LS API和实现进行一次全面的审查,看看从迭代器/生成器中能获得什么好处是有意义的。