我有一个任务要在组件加载之前从Amazon S3存储桶加载3个脚本,因为它使用了此脚本中的逻辑。因此,我有一个解析器,该脚本将脚本标签添加到 HEAD :
private scripts: ScriptModel[] = [];
private envScripts: ScriptModel[];
constructor(
private appState: AppState
) {
// empty
}
public resolve() {
console.log('Resolver');
const environment = this.appState.restore('environment');
forkJoin(this.load(environment))
.subscribe(
() => { /* empty */ console.log('Scripts loaded'); },
(error: any) => { console.log(`Error to load scripts for preview: `, error); }
);
}
public load(env: string) {
this.envScripts = ScriptStore[env].map((_script: ScriptModel) => ({ name: _script.name, src: _script.src, loaded: _script.loaded }));
const scripts: ScriptModel[] = this.envScripts.map((_script: ScriptModel) => this.loadScript(_script));
return scripts;
}
public loadScript(script: ScriptModel) {
return Observable.create((observer: Observer<ScriptModel>) => {
const existingScript = this.scripts.find((_script: ScriptModel) => _script.name === script.name);
if (!!existingScript && existingScript.loaded) {
observer.next(existingScript);
observer.complete();
} else {
this.scripts = [...this.scripts, script];
const scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.src = script.src;
scriptElement.onload = () => {
script.loaded = true;
observer.next(script);
observer.complete();
};
scriptElement.onerror = () => {
observer.error(`Couldn't load script ${script.name}, ${script.src}`);
};
document.querySelector('head').appendChild(scriptElement);
}
});
}
ScriptStore根据环境名称包含脚本,ScriptModel是描述其外观的接口:
export interface ScriptModel {
name: string;
src: string;
loaded: boolean;
}
我有一个问题,有时组件中的代码会引发错误,这些附加脚本的功能未定义。据我了解,这是因为组件中的代码会在加载这些脚本之前执行。在组件中,一些代码开始在构造函数中工作,而主函数在 ngOnInit 中调用。但是在解析器完成之前,不应加载该组件。我需要在解析器中返回一些 Observable / Promise 吗?我应该如何正确地做呢?仅当所有脚本都已加载时,解析程序才必须完成。我使用Observables来控制是否加载了脚本,而在解析器之前,它是具有诺言的服务,但是它也会引发相同的错误。