在开发应用时,有些功能不太常用但却必须有( 比如编辑器)。直接集成到项目里又会增加主包(main.js)的大小。为了避免这些问题,通过懒加载的方式似乎比较好。
具体实现请看线上例子:angular-lazy-loading-lib-lddvq1f - StackBlitz,代码比较简单就不赘述了。只提几点关键的。
- 以rxjs的ReplaySubject实现: https://rxjs-dev.firebaseapp.com/api/index/class/ReplaySubject
A variant of Subject that "replays" or emits old values to new subscribers. It buffers a set number of values and will emit those values immediately to any new subscribers in addition to emitting new values to existing subscribers.
private loadedLibraries: { [url: string]: ReplaySubject<any> } = {};
2. 当然若请求资源发生了异常则需要捕获,所以使用了原生的XMLHttpRequest来预先请求。
private _load(url: string, cb: (replaySubject$: ReplaySubject<any>) => Element): Observable<any> {
if (this.loadedLibraries[url]) {
return this.loadedLibraries[url].asObservable();
}
const element = cb(this.loadedLibraries[url] = new ReplaySubject());
// 骚操作,先用原生方法获取url的资源,若失败则返回错误
// https://stackoverflow.com/questions/28556398/how-to-catch-neterr-connection-refused
return new Observable((ob: Observer<any>) => {
request(url)
.then(() => {
this.document.body.appendChild(element);
// 加载js或css触发onload后
this.loadedLibraries[url].subscribe(() => {
ob.next('');
ob.complete();
});
})
.catch(err => {
this.loadedLibraries[url] = null;
// 这里可以弹窗提示刷新或者手动再次调用加载等等操作
console.error('LazyLoadingLibService error', err);
ob.error(err);
ob.complete();
});
});
}
3.加载js
public loadJS(url: string): Observable<any> {
return this._load(url, (replaySubject$: ReplaySubject<any>) => {
const script = this.document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = () => {
replaySubject$.next('');
replaySubject$.complete();
};
return script;
});
}
4. 第三方库的引用地址:https://unpkg.com/ ,如果你不想打包那么多的js,那么这个地址将会有所帮助。
5. 当然这样的操作是有弊端的,就是没有代码提示的。不过用得少也不纠结了。
参考地址:
https://stackoverflow.com/questions/46240293/how-to-lazyload-library-in-angular-4-module