Skip to content

Instantly share code, notes, and snippets.

@everettcaleb
Created December 18, 2018 16:33
Show Gist options
  • Save everettcaleb/a11a75e93108f130074eb92b5c12716f to your computer and use it in GitHub Desktop.
Save everettcaleb/a11a75e93108f130074eb92b5c12716f to your computer and use it in GitHub Desktop.
service-injection-poc created by everettcaleb - https://repl.it/@everettcaleb/service-injection-poc
const { camelCase } = require('lodash')
class ServiceProvider {
constructor() {
this.services = {}
this.cleanupList = []
this.injector = new Proxy(this.services, { get: (...x) => this.getServiceByProxy(...x) })
}
cleanup() {
let service = this.cleanupList.pop()
while(service) {
service.cleanup()
service = this.cleanupList.pop()
}
this.services = {}
}
get(name) {
return getServiceByProxy(this.services, name)
}
getServiceByProxy(services, name) {
console.log('Injecting', name)
const service = services[name]
if(!service) {
throw new Error('Failed to inject', name)
}
return service.load(this)
}
register(name, factory, { cleanup, persist, preload } = {}) {
console.log('Registering', name, factory)
const service = new Service(factory, { cleanup, persist, preload })
service.preload(this)
this.services[name] = service
return this
}
registerConst(name, val, { cleanup } = {}) {
return this.register(name, () => val, { cleanup, persist: true, preload: true })
}
registerConstructor(ctor, { cleanup, persist, preload } = {}) {
return this.register(camelCase(ctor.name), injector => new ctor(injector), { cleanup, persist, preload })
}
}
class Service {
constructor(factory, { cleanup, persist, preload } = {}) {
this._factoryFunction = factory
this._cleanupFunction = cleanup
this._persist = persist || preload || cleanup
this._preload = preload
this._instance = null
}
cleanup() {
if(this._persist && this._cleanupFunction && this._instance) {
this._cleanupFunction(this._instance)
}
}
load(provider) {
const inst = this._instance || this._factoryFunction(provider.injector)
if(!this._instance && this._cleanupFunction) {
provider.cleanupList.push(this)
}
if(this._persist) {
this._instance = inst
}
return inst
}
preload(provider) {
if(this._preload) {
this.load(provider)
}
}
}
const sp = new ServiceProvider()
class FooService {
constructor({ barService }) {
console.log('FooService ctor')
this.barService = barService
}
doFoo() {
console.log('FOO')
this.barService.doBar()
}
}
class BarService {
constructor() {
console.log('BarService ctor')
}
doBar() {
console.log('BAR')
}
}
class MyController {
constructor({ fooService, barService, LIFE }) {
console.log('MyController ctor')
this.life = LIFE
this.fooService = fooService
this.barService = barService
}
doFooBar() {
console.log('FOOBARBAR')
console.log(this.life)
this.fooService.doFoo()
this.barService.doBar()
}
}
// TEST CODE BELOW
// register services
sp.registerConst('LIFE', 42)
sp.registerConstructor(BarService, { persist: true, cleanup: () => console.log('CLEAN BAR') })
sp.registerConstructor(FooService, { cleanup: () => console.log('CLEAN FOO')})
// load controller and run the logic
const ctrl = new MyController(sp.injector)
ctrl.doFooBar()
sp.cleanup()
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"pluralize": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
}
}
}
{
"main": "index.js",
"dependencies": {
"lodash": "4.17.11",
"pluralize": "7.0.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment