Merge pull request #15 from pese-git/improve

perf(scope): speed up dependency lookup with Map-based binding resolv…
This commit is contained in:
Sergey Penkovsky
2025-08-07 16:19:11 +03:00
committed by GitHub
4 changed files with 37 additions and 9 deletions

View File

@@ -94,6 +94,13 @@ final subScope = rootScope.openSubScope('featureScope')
final dataBloc = await subScope.resolveAsync<DataBloc>();
```
### Fast Dependency Lookup (Performance Improvement)
> **Performance Note:**
> **Starting from version 3.0.0**, CherryPick uses a Map-based resolver index for dependency lookup. This means calls to `resolve<T>()` and related methods are now O(1) operations, regardless of the number of modules or bindings in your scope. Previously, the library had to iterate over all modules and bindings to locate the requested dependency, which could impact performance as your project grew.
>
> This optimization is internal and does not change any library APIs or usage patterns, but it significantly improves resolution speed in larger applications.
### Dependency Lookup API
- `resolve<T>()` — Locates a dependency instance or throws if missing.

View File

@@ -39,6 +39,10 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
final Set<Module> _modulesList = HashSet();
// индекс для мгновенного поиска bindingов
final Map<Object, Map<String?, BindingResolver>> _bindingResolvers = {};
/// RU: Генерирует уникальный идентификатор для скоупа.
/// ENG: Generates unique identifier for scope.
String _generateScopeId() {
@@ -96,6 +100,7 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
for (var module in modules) {
module.builder(this);
}
_rebuildResolversIndex();
return this;
}
@@ -107,7 +112,7 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
Scope dropModules() {
// [AlexeyYuPopkov](https://github.com/AlexeyYuPopkov) Thank you for the [Removed exception "ConcurrentModificationError"](https://github.com/pese-git/cherrypick/pull/2)
_modulesList.clear();
_rebuildResolversIndex();
return this;
}
@@ -253,17 +258,18 @@ class Scope with CycleDetectionMixin, GlobalCycleDetectionMixin {
_parentScope?.tryResolveAsync(named: named, params: params);
}
BindingResolver<T>? _findBindingResolver<T>(String? named) {
BindingResolver<T>? _findBindingResolver<T>(String? named) =>
_bindingResolvers[T]?[named] as BindingResolver<T>?;
// Индексируем все bindingи после каждого installModules/dropModules
void _rebuildResolversIndex() {
_bindingResolvers.clear();
for (var module in _modulesList) {
for (var binding in module.bindingSet) {
if (binding.key == T &&
((!binding.isNamed && named == null) ||
(binding.isNamed && named == binding.name))) {
return binding.resolver as BindingResolver<T>?;
}
_bindingResolvers.putIfAbsent(binding.key, () => {});
final nameKey = binding.isNamed ? binding.name : null;
_bindingResolvers[binding.key]![nameKey] = binding.resolver!;
}
}
return null;
}
}

View File

@@ -177,6 +177,14 @@ final service = scope.tryResolve<OptionalService>(); // returns null if not exis
---
### Fast Dependency Lookup (Performance Improvement)
> **Performance Note:**
> **Starting from version 3.0.0**, CherryPick uses a Map-based resolver index for dependency lookup. This means calls to `resolve<T>()`, `tryResolve<T>()` and similar methods are now O(1) operations, regardless of the number of modules or bindings within your scope. Previously it would iterate over all modules and bindings, which could reduce performance as your project grew. This optimization is internal and does not affect the public API or usage patterns, but significantly improves resolution speed for larger applications.
---
## Dependency injection with annotations & code generation
CherryPick supports DI with annotations, letting you eliminate manual DI setup.

View File

@@ -178,6 +178,13 @@ final service = scope.tryResolve<OptionalService>(); // вернет null, ес
---
### Быстрый поиск зависимостей (Performance Improvement)
> **Примечание по производительности:**
> Начиная с версии **3.0.0**, CherryPick для поиска зависимости внутри scope использует Map-индекс. Благодаря этому методы `resolve<T>()`, `tryResolve<T>()` и аналогичные теперь работают за O(1), независимо от количества модулей и биндингов в вашем проекте. Ранее для поиска приходилось перебирать весь список вручную, что могло замедлять работу крупных приложений. Это внутреннее улучшение не меняет внешнего API или паттернов использования, но заметно ускоряет разрешение зависимостей на больших проектах.
---
## Внедрение зависимостей через аннотации и автогенерацию
CherryPick поддерживает DI через аннотации, что позволяет полностью избавиться от ручного внедрения зависимостей.