How to dynamically bind a dynamically imported type

萝らか妹 提交于 2019-12-13 02:19:15

问题


I am trying to have templates automagically wired to an inversifyjs container but whatever I try it's not working. Please help?

private templates = [
    {file: './component.html.tpl', obj: 'HtmlTemplate'},
    {file: './component.tpl.ts', obj: 'ComponentTemplate'}
];
private container = new Container();
bind(){
    // original and working code 
    // this.container.bind<ITemplate>('HtmlTemplate').to(HtmlTemplate);
    // this.container.bind<ITemplate>('ComponentTemplate').to(ComponentTemplate);
    this.templates.forEach(template => {
        import(template.file).then(mod => {
            console.log(mod.default, template);
            // is this correct (seems to work) => 
            this.container.bind<ITemplate>(template.obj).to(mod.default);
            console.log('bound =>', mod.default);
        });
    });
}

and files ./component.html.tpl

@injectable() export default class HtmlTemplate implements ITemplate { ... }

and ./component.ts.tpl

@injectable() export default class ComponentTemplate implements ITemplate { ... }

Which logs completely as expected to the console:

[Function: HtmlTemplate] { file: './component.html.tpl', obj: 'HtmlTemplate' }
[Function: ComponentTemplate] { file: './component.tpl.ts', obj: 'ComponentTemplate' }

But I really expected the code in the foreach statement:

this.container.bind<ITemplate>(template.obj).to(mod.default);

to be equivalent to this:

this.container.bind<HtmlTemplate>('HtmlTemplate').to(HtmlTemplate);
this.container.bind<ComponentTemplate>('ComponentTemplate').to(ComponentTemplate);

but when I try to resolve it in an other loop:

this.templates.forEach(template => {
    const tpl = this.container.get<ITemplate>(template.obj);
...

it throws an error:

Error: No matching bindings found for serviceIdentifier HtmlTemplate

Anyone know how to solve this?


回答1:


The code has problems with control flow. There are promises that aren't chained, which is antipattern. This results in inefficient error handling and race conditions.

Each and every promise should be chained. The use of forEach is discouraged in ES6 for several reasons, one of them is that it requires additional actions to work with promises and doesn't work well with generators and async functions. The code can take most of async functions and be refactored to make control flow clean and efficient:

async bind(){
    for (const template of this.templates)
       const mod = await import(template.file);
       this.container.bind<ITemplate>(template.obj).to(mod.default);
    }
}

The code that uses bind should chain it and avoid promise construction antipatterns:

async bind() {
    // binding for when the widget is needed;
    for (const component of this.components)
        component.widget = this.container.get<Widget>(component.name);
        if(component.widget) {
            await component.widget.configure();
            await component.widget.bind();
        } else {
            console.error(`widget ${component.name} not resolved`);
        }
    });

    return this;
}

A more efficient way is to discard asynchronous initialization routine, because the only thing that requires it is dynamic import(). import() promises can be replaced with synchronous require statements, import() falls back to require in Node.js any way.



来源:https://stackoverflow.com/questions/50328582/how-to-dynamically-bind-a-dynamically-imported-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!