我有一个Angular 1应用程序,我试图提高进行大量计算的特定服务的性能(可能没有优化,但除此之外,在另一个线程中运行它是目标权利现在增加动画表现)
该应用运行您的GPA,条款,课程分配等计算。服务名称为calc
。 Inside 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兼容性构建服务
一个。 将其结构与现在完全相同
湾替换为Web Worker“代理”(正确的术语?)服务
问题是如何创建Web Worker“Proxy”以维护与其余代码相同的服务行为。
我想要的一些事情:
...我想到目前为止还没有真正的问题,这只是对问题的解释......所以没有进一步的麻烦......
使用Angular服务工厂检测Web Worker兼容性的最佳方法是什么,有条件地将服务实现为Web Worker ,同时保持相同服务行为,为非Web Worker兼容浏览器保留 DRY代码和维护支持?
我也看了VKThread,这可能有助于我的情况,但我不确定如何最好地实施它。
更多资源:
答案 0 :(得分:2)
一般而言,制作可在工作中运行的可管理代码的好方法 - 尤其是也可以在同一窗口中运行的代码(例如,当不支持worker时)是使代码事件驱动然后使用简单代理通过通信渠道驱动事件 - 在本例中为worker。
我首先创建了抽象"类"这并没有真正定义向另一方发送事件的方式。
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);
}
然后你为worker实现这个例子:
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索引它们。但肯定可行,如果您从不同的来源调用工作者功能,可能会更好。
答案 1 :(得分:0)
我是问题中提到的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/
希望这有帮助,
- 瓦迪姆