![Page 1: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/1.jpg)
Dependency Injection. Javascript.
Сергей Камардин
![Page 2: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/2.jpg)
Задача из жизни
1. Разместить на карте зарегистрированных пользователей;
!
2
![Page 3: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/3.jpg)
«JS Way»Locator.prototype.locateUsers = function(users) { // Инициалиация сервиса карт loadScript("..."); client.init(...); ! // Создание карты var map = new client.Map(...); ! // Отображение на карте маркеров users.forEach(...); }
3
![Page 4: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/4.jpg)
Задача из жизни
1. Разместить на карте зарегистрированных пользователей;
2. Поменять поставщика карт;
4
![Page 5: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/5.jpg)
Решение: АбстракцияAbstractMapService.prototype = { ! createMap: function() { throw new TypeError("Not implemented"); }, ! createMapMarker: function() { throw new TypeError("Not implemented"); } !}
5
![Page 6: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/6.jpg)
ИмплементацияAbstractMapService.extend({ ! createMap: function(id, options) { // }, ! createMapMarker: function(map, options) { // } !});
6
![Page 7: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/7.jpg)
Locator.prototype.locateUsers = function(users) { // Create map service // Could be an Fabric Method, Service Locator, DI var mapService = new ConcreteMapService(...); ! // Create map var map = mapService.createMap(...); ! // Run each users, making markers users.forEach(...); }
7
![Page 8: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/8.jpg)
Single responsibility?Locator.prototype.locateUsers = function(users) { // Create map service // Could be an Fabric Method, Service Locator, DI var mapService = new ConcreteMapService(...); ! // Create map var map = mapService.createMap(...); ! // Run each users, making markers users.forEach(...); }
8
![Page 9: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/9.jpg)
Проблемы
• Невозможно написать юнит тесты;
• Использование сервиса карт во многих местах в коде;
• Избыточная функциональность локатора;
• Reusability.
9
![Page 10: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/10.jpg)
Задача из жизни
1. Разместить на карте зарегистрированных пользователей;
2. Поменять поставщика карт;
3. Перенести локатор в другой проект, как плагин.
10
![Page 11: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/11.jpg)
ResultLocator.prototype = { // injection setMapService: function(mapService) { this.mapService = mapService; }, ! locateUsers: function(users) { // Create map var map = this.mapService.createMap(...); ! // Run each users, making markers users.forEach(...); } }
11
![Page 12: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/12.jpg)
12
![Page 13: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/13.jpg)
ResultLocator.prototype = { // injection setMapService: function(mapService) { this.mapService = mapService; }, ! locateUsers: function(users) { // Create map var map = this.mapService.createMap(...); ! // Run each users, making markers users.forEach(...); } }
13
Вот оно
![Page 14: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/14.jpg)
Routine// Create MapService var mapService = new MapService(...); !// Create Locator var locator = new Locator(); !// Inject mapService locator.setMapService(mapService); !// Use locator locator.locateUsers(users);
14
![Page 15: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/15.jpg)
Inversion of Control
• Dependency Injection
• Service Locator
• Factory Method
IoC container:
15
![Page 16: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/16.jpg)
Dependency Injection
• Constructor injection
• Setter injection
• Interface injection
16
![Page 17: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/17.jpg)
Hard Coupling
17
![Page 18: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/18.jpg)
Coupling
18
![Page 19: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/19.jpg)
Loose Coupling
19
![Page 20: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/20.jpg)
Плюсы• Каждый объект отвечает за свою функцию;
• Соблюден принцип инверсии зависимостей;
• Простая конфигурация объектов;
• Безболезненная смена имплементаций;
• Легко писать юнит тесты.
20
![Page 21: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/21.jpg)
dm.js
• Javascript Реализация IoC;
• Работает в node.js и браузере;
• Легко расширяется (любые загрузчики скриптов и Promise/A+ библиотеки);
• Простая конфигурация (в духе Symfony).
21
![Page 22: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/22.jpg)
Конфигурация "locator": { path: "path/to/locator/implementation", calls: [ ["setMapService", ["@maps"]] ] } "maps": { path: "path/to/map/service/implementation", arguments: [{ id: "my-app-id" }] }
22
![Page 23: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/23.jpg)
Использование
dm .get("locator") .then(function(locator) { locator.locateUsers(users); });
23
![Page 24: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/24.jpg)
Тестированиеit("should create map", function() { var mapStub, locator; ! mapMock = sinon .mock(new AbstractMapService) .expects("createMap") .once(); ! locator = new Locator(); locator.setMapService(mapMock); ! locator.locateUsers(...); ! mapMock.verify(); });
24
![Page 25: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/25.jpg)
Syntax! "example": { "path": "...", "arguments": [{ "service": "@service", "method": "@service:method" "result": "@service:method[1,2,3]", "resource": "#path/to/my.tpl#", "path": "http://%{api_path}" "build": "build_no_#{file.txt}" }] } !
25
![Page 26: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/26.jpg)
Альтернативы
• Wire.js
• Angular’s DI
• Тупо контейнеры
26
![Page 27: "Dependency Injection. JavaScript.", Сергей Камардин, MoscowJS 15](https://reader035.vdocuments.mx/reader035/viewer/2022081800/55762419d8b42a4e1c8b4ecb/html5/thumbnails/27.jpg)
Где и для чего это можно использовать?
27