Как динамически связать динамически импортируемый тип - PullRequest
0 голосов
/ 14 мая 2018

Я пытаюсь, чтобы шаблоны автоматически подключались к контейнеру inversifyjs, но что бы я ни пытался, это не работает.Пожалуйста, помогите?

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);
        });
    });
}

и файлам ./component.html.tpl

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

и ./component.ts.tpl

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

Что регистрирует полностьюкак и ожидалось консоли:

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

Но я действительно ожидал, что код в выражении foreach:

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

будет эквивалентен этому:

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

но когда я пытаюсь разрешить его в другом цикле:

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

выдает ошибку:

Error: No matching bindings found for serviceIdentifier HtmlTemplate

Кто-нибудь знает, как решить эту проблему?

1 Ответ

0 голосов
/ 15 мая 2018

Код имеет проблемы с потоком управления.Есть обещания, которые не связаны, что является антипаттерном.Это приводит к неэффективной обработке ошибок и условиям гонки.

Каждое обещание должно быть приковано цепью.Использование forEach не рекомендуется в ES6 по нескольким причинам, одна из них заключается в том, что для работы с обещаниями требуются дополнительные действия, и он не очень хорошо работает с генераторами и async функциями.Код может принимать большинство функций async и подвергаться рефакторингу, чтобы сделать поток управления чистым и эффективным:

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

Код, использующий bind, должен связать его в цепочку и избежать создания шаблонных обещаний:

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;
}

Более эффективный способ - отказаться от процедуры асинхронной инициализации, потому что единственное, что для этого требуется - это динамический import().import() обещания могут быть заменены синхронными require операторами, import() в любом случае возвращается к require в Node.js.

...