让我们有一个角度项目。出于性能原因,我们希望应用程序在webworkers中运行,这是可以的,因为Angular团队有可能这样做。
我们的应用程序需要实现DOM操作库(谷歌地图)。因此我们需要使这个模块在主线程上运行,在那里可以进行DOM操作。但是,我们仍然希望在网络工作者中完成所有繁重的工作。
为了解决这个问题,我将所有对外部库的调用都包含在一个文件中。为方便起见,此文件是模块的服务。
map
- component.ts
- service.ts
- module.ts
- template.html
- styles.css
export class MapComponent implements OnInit, OnDestroy {
constructor(private mapService: MapService, element: ElementRef, renderer: Renderer2)
this.mapService.element.then(map => {
renderer.appendChild(element.nativeElement, map)
})
}
}
@Injectable()
export class MapService {
private static worker = new Worker('./worker.js')
public map: google.maps.Map
public element: Promise<Element>
constructor(private http: Http) {
const div = document.createElement('div')
this.map = new google.maps.Map(div, { ... })
this.element = new Promise(resolve => {
// Fetch google map div element as soon as it is availe
google.maps.event.addDomListenerOnce(this.map, 'idle', () => {
resolve(this.map.getDiv())
})
})
MapService.worker.postMessage({ name: 'init', data: ... }])
MapService.worker.addEventListener('message', event => { ... })
}
}
template.html
只包含<content></content>
。组件从外部库请求map元素的服务,它是一个div
,然后通过renderer.appendChild(element.nativeElement, div)
添加这个div。函数renderer.appendChild
是安全的,但我不确定DOM元素是否能够传递给worker。
要回答的问题:
笔记:
encapsulation: ViewEncapsulation.Native
我认为angular没有默认支持在web worker中运行某些模块而在主线程中运行一些模块。 angular中提供的默认支持是使用“platform-webworker”和“platform-werbworker-dynamic”模块在Web工作线程中运行所有业务逻辑(组件和服务)。要使用此解决方案,您需要确保您的应用程序没有对组件和服务中的窗口,dom,文档等进行任何直接引用。
如果很难修改现有应用程序以使其与Web worker兼容,您仍然可以使用Web worker在Web worker线程中运行一些cpu密集型代码/逻辑,并且应用程序的其余部分可以继续在主线程中运行。
这是一个演讲,讨论如何做到这一点:Web Workers In Your Angular Application
来自Angular 5和Angular 6的演示文稿示例的源代码
希望你会发现这很有帮助。