Angular 服务和网络工作者
Angular Service and Web Workers
我有一个 Angular 1 应用程序,我正在尝试提高进行大量计算的特定服务的性能(并且可能没有优化,但现在除此之外,运行 它在另一个线程中是现在提高动画性能的目标)
应用程序
该应用程序对您的 GPA、学期、课程作业等进行计算。服务名称是 calc
。在 Calc 中有 user
、term
、course
和 assign
命名空间。每个命名空间都是一个对象,格式如下
{
//Times for the calculations (for development only)
times:{
//an array of calculation times for logging and average calculation
array: []
//Print out the min, max average and total calculation times
report: function(){...}
},
//Hashes the object (with service.hash()) and checks to see if we have cached calculations for the item, if not calls runAllCalculations()
refresh: function(item){...},
//Runs calculations, saves it in the cache (service.calculations array) and returns the calculation object
runAllCalculations: function(item){...}
}
这是来自 IntelliJ 非常好的结构选项卡的屏幕截图,有助于可视化
需要做什么?
检测 Web Worker 兼容性 (MDN)
根据 Web Worker 兼容性构建服务
一个。 结构与现在完全相同
b。替换为 Web Worker "proxy"(术语正确?)service
问题
问题是如何创建 Web Worker "Proxy" 以保持与其余代码相同的服务行为。
Requirements/Wants
我想要的一些东西:
- 最重要的是,如上所述,保持服务行为不变
- 要为服务保留一个代码库,请保持 DRY,而不必修改两个点。为此,我查看了 WebWorkify,但我不确定如何最好地实施它。
- 在等待 worker 完成时使用 Promises
- 再次使用 Angular 和 worker 内部的其他服务(如果可能的话)WebWorkify 似乎可以解决这个问题
问题
...我想到目前为止还没有真正的问题,这只是对问题的解释...所以事不宜迟...
使用 Angular 服务工厂 检测 Web Worker 兼容性的最佳方法是什么,有条件地 将服务实现为 Web Worker,同时保持相同的服务行为,保持DRY代码和维护支持 Web Worker 兼容的浏览器?
其他注意事项
我也看过VKThread,这可能对我的情况有所帮助,但我不确定如何最好地实施它。
更多资源:
一般来说,制作可在 worker 中运行的可管理代码的好方法 - 尤其是在同一 window 中也可以 运行 的代码(例如,当不支持 worker 时)是使代码成为事件驱动的,然后使用简单的代理通过通信渠道驱动事件——在本例中为 worker。
我首先创建了抽象 "class",它并没有真正定义向另一方发送事件的方式。
function EventProxy() {
// Object that will receive events that come from the other side
this.eventSink = null;
// This is just a trick I learned to simulate real OOP for methods that
// are used as callbacks
// It also gives you refference to remove callback
this.eventFromObject = this.eventFromObject.bind(this);
}
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// This is not implemented. We should have WorkerProxy inherited class.
throw new Error("This is abstract method. Object dispatched an event "+
"but this class doesn't do anything with events.";
}
EventProxy.prototype.setObject = (object)=> {
// If object is already set, remove event listener from old object
if(this.eventSink!=null)
//do it depending on your framework
... something ...
this.eventSink = object;
// Listen on all events. Obviously, your event framework must support this
object.addListener("*", this.eventFromObject);
}
// Child classes will call this when they receive
// events from other side (eg. worker)
EventProxy.prototype.eventReceived = (name, args)=> {
// put event name as first parameter
args.unshift(name);
// Run the event on the object
this.eventSink.dispatchEvent.apply(this.eventSink, args);
}
然后你为工人实现这个,例如:
function WorkerProxy(worker) {
// call superconstructor
EventProxy.call(this);
// worker
this.worker = worker;
worker.addEventListener("message", this.eventFromWorker = this.eventFromWorker.bind(this));
}
WorkerProxy.prototype = Object.create(EventProxy.prototype);
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// include event args but skip the first one, the name
var args = [];
args.push.apply(args, arguments);
args.splice(0, 1);
// Send the event to the script in worker
// You could use additional parameter to use different proxies for different objects
this.worker.postMessage({type: "proxyEvent", name:name, arguments:args});
}
EventProxy.prototype.eventFromWorker = (event)=>{
if(event.data.type=="proxyEvent") {
// Use superclass method to handle the event
this.eventReceived(event.data.name, event.data.arguments);
}
}
那么用法就是你有一些服务和一些接口,在你做的页面代码中:
// Or other proxy type, eg socket.IO, same window, shared worker...
var proxy = new WorkerProxy(new Worker("runServiceInWorker.js"));
//eg user clicks something to start calculation
var interface = new ProgramInterface();
// join them
proxy.setObject(interface);
而在 runServiceInWorker.js
中你做的几乎一样:
importScripts("myservice.js", "eventproxy.js");
// Here we're of course really lucky that web worker API is symethric
var proxy = new WorkerProxy(self);
// 1. make a service
// 2. assign to proxy
proxy.setObject(new MyService());
// 3. profit ...
根据我的经验,有时我不得不检测我在哪一边,但那是使用不对称的网络套接字(有服务器和许多客户端)。您可能 运行 遇到与共享工作人员类似的问题。
您提到了 Promises - 我认为 promises 的方法是相似的,但可能更复杂,因为您需要将回调存储在某个地方并通过请求的 ID 对它们进行索引。但肯定是可行的,如果你从不同的来源调用辅助函数,可能会更好。
我是问题中提到的vkThread插件的作者。是的,我开发了 Angular version of vkThread plugin,它允许您在单独的线程中执行函数。
函数可以直接在主线程中定义或从外部 javascript 文件中调用。
函数可以是:
- 常规函数
- 对象的方法
- 具有依赖性的函数
- 具有上下文的函数
- 匿名函数
基本用法:
/* function to execute in a thread */
function foo(n, m){
return n + m;
}
// to execute this function in a thread: //
/* create an object, which you pass to vkThread as an argument*/
var param = {
fn: foo // <-- function to execute
args: [1, 2] // <-- arguments for this function
};
/* run thread */
vkThread.exec(param).then(
function (data) {
console.log(data); // <-- thread returns 3
}
);
示例和 API 文档:http://www.eslinstructor.net/ng-vkthread/demo/
希望这对您有所帮助,
--瓦迪姆
我有一个 Angular 1 应用程序,我正在尝试提高进行大量计算的特定服务的性能(并且可能没有优化,但现在除此之外,运行 它在另一个线程中是现在提高动画性能的目标)
应用程序
该应用程序对您的 GPA、学期、课程作业等进行计算。服务名称是 calc
。在 Calc 中有 user
、term
、course
和 assign
命名空间。每个命名空间都是一个对象,格式如下
{
//Times for the calculations (for development only)
times:{
//an array of calculation times for logging and average calculation
array: []
//Print out the min, max average and total calculation times
report: function(){...}
},
//Hashes the object (with service.hash()) and checks to see if we have cached calculations for the item, if not calls runAllCalculations()
refresh: function(item){...},
//Runs calculations, saves it in the cache (service.calculations array) and returns the calculation object
runAllCalculations: function(item){...}
}
这是来自 IntelliJ 非常好的结构选项卡的屏幕截图,有助于可视化
需要做什么?
检测 Web Worker 兼容性(MDN)根据 Web Worker 兼容性构建服务
一个。
结构与现在完全相同b。替换为 Web Worker "proxy"(术语正确?)service
问题
问题是如何创建 Web Worker "Proxy" 以保持与其余代码相同的服务行为。
Requirements/Wants
我想要的一些东西:
- 最重要的是,如上所述,保持服务行为不变
- 要为服务保留一个代码库,请保持 DRY,而不必修改两个点。为此,我查看了 WebWorkify,但我不确定如何最好地实施它。
- 在等待 worker 完成时使用 Promises
- 再次使用 Angular 和 worker 内部的其他服务(如果可能的话)WebWorkify 似乎可以解决这个问题
问题
...我想到目前为止还没有真正的问题,这只是对问题的解释...所以事不宜迟...
使用 Angular 服务工厂 检测 Web Worker 兼容性的最佳方法是什么,有条件地 将服务实现为 Web Worker,同时保持相同的服务行为,保持DRY代码和维护支持 Web Worker 兼容的浏览器?
其他注意事项
我也看过VKThread,这可能对我的情况有所帮助,但我不确定如何最好地实施它。
更多资源:
一般来说,制作可在 worker 中运行的可管理代码的好方法 - 尤其是在同一 window 中也可以 运行 的代码(例如,当不支持 worker 时)是使代码成为事件驱动的,然后使用简单的代理通过通信渠道驱动事件——在本例中为 worker。
我首先创建了抽象 "class",它并没有真正定义向另一方发送事件的方式。
function EventProxy() {
// Object that will receive events that come from the other side
this.eventSink = null;
// This is just a trick I learned to simulate real OOP for methods that
// are used as callbacks
// It also gives you refference to remove callback
this.eventFromObject = this.eventFromObject.bind(this);
}
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// This is not implemented. We should have WorkerProxy inherited class.
throw new Error("This is abstract method. Object dispatched an event "+
"but this class doesn't do anything with events.";
}
EventProxy.prototype.setObject = (object)=> {
// If object is already set, remove event listener from old object
if(this.eventSink!=null)
//do it depending on your framework
... something ...
this.eventSink = object;
// Listen on all events. Obviously, your event framework must support this
object.addListener("*", this.eventFromObject);
}
// Child classes will call this when they receive
// events from other side (eg. worker)
EventProxy.prototype.eventReceived = (name, args)=> {
// put event name as first parameter
args.unshift(name);
// Run the event on the object
this.eventSink.dispatchEvent.apply(this.eventSink, args);
}
然后你为工人实现这个,例如:
function WorkerProxy(worker) {
// call superconstructor
EventProxy.call(this);
// worker
this.worker = worker;
worker.addEventListener("message", this.eventFromWorker = this.eventFromWorker.bind(this));
}
WorkerProxy.prototype = Object.create(EventProxy.prototype);
// Object get this as all events callback
// typically, you will extract event parameters from "arguments" variable
EventProxy.prototype.eventFromObject = (name)=>{
// include event args but skip the first one, the name
var args = [];
args.push.apply(args, arguments);
args.splice(0, 1);
// Send the event to the script in worker
// You could use additional parameter to use different proxies for different objects
this.worker.postMessage({type: "proxyEvent", name:name, arguments:args});
}
EventProxy.prototype.eventFromWorker = (event)=>{
if(event.data.type=="proxyEvent") {
// Use superclass method to handle the event
this.eventReceived(event.data.name, event.data.arguments);
}
}
那么用法就是你有一些服务和一些接口,在你做的页面代码中:
// Or other proxy type, eg socket.IO, same window, shared worker...
var proxy = new WorkerProxy(new Worker("runServiceInWorker.js"));
//eg user clicks something to start calculation
var interface = new ProgramInterface();
// join them
proxy.setObject(interface);
而在 runServiceInWorker.js
中你做的几乎一样:
importScripts("myservice.js", "eventproxy.js");
// Here we're of course really lucky that web worker API is symethric
var proxy = new WorkerProxy(self);
// 1. make a service
// 2. assign to proxy
proxy.setObject(new MyService());
// 3. profit ...
根据我的经验,有时我不得不检测我在哪一边,但那是使用不对称的网络套接字(有服务器和许多客户端)。您可能 运行 遇到与共享工作人员类似的问题。
您提到了 Promises - 我认为 promises 的方法是相似的,但可能更复杂,因为您需要将回调存储在某个地方并通过请求的 ID 对它们进行索引。但肯定是可行的,如果你从不同的来源调用辅助函数,可能会更好。
我是问题中提到的vkThread插件的作者。是的,我开发了 Angular version of vkThread plugin,它允许您在单独的线程中执行函数。
函数可以直接在主线程中定义或从外部 javascript 文件中调用。
函数可以是:
- 常规函数
- 对象的方法
- 具有依赖性的函数
- 具有上下文的函数
- 匿名函数
基本用法:
/* function to execute in a thread */
function foo(n, m){
return n + m;
}
// to execute this function in a thread: //
/* create an object, which you pass to vkThread as an argument*/
var param = {
fn: foo // <-- function to execute
args: [1, 2] // <-- arguments for this function
};
/* run thread */
vkThread.exec(param).then(
function (data) {
console.log(data); // <-- thread returns 3
}
);
示例和 API 文档:http://www.eslinstructor.net/ng-vkthread/demo/
希望这对您有所帮助,
--瓦迪姆