首页 文章

角度服务和Web工作者

提问于
浏览
3

我有一个Angular 1应用程序,我正在尝试提高进行大量计算的特定服务的性能(并且可能没有进行优化,但除此之外,在另一个线程中运行它是目前增加的目标动画表演)

该应用程序

该应用程序在您的GPA,条款,课程作业等上运行计算 . 服务名称为 calc . 在Calc里面有 usertermcourseassign 名称空间 . 每个命名空间都是以下形式的对象

{
    //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兼容性构建服务

一个 . 结构与现在完全相同

湾替换为Web Worker“代理”(正确的术语?)服务

问题

问题是如何创建Web Worker“代理”以维护与其余代码相同的服务行为 .

要求/想要

我想要的一些事情:

  • 最重要的是,如上所述,保持服务行为不变

  • 要为服务保留一个代码库,请保持 DRY ,而不必修改两个位置 . 我已经看了WebWorkify,但我不确定如何最好地实现它 .

  • 在等待 Worker 完成时使用Promises

  • 在 Worker 内部使用Angular和可能的其他服务(如果可能的话)WebWorkify似乎也解决了这个问题

问题

......我想到目前为止还没有真正的问题,这只是对问题的解释......所以没有进一步的...

什么是使用Angular服务工厂 detect Web Worker compatibility ,有条件 implement the service as a Web Worker ,同时保留 same service behavior ,保持 DRY codemaintaining support 非Web Worker兼容浏览器的最佳方法?

其他说明

我也看了VKThread,这可能能够帮助解决我的情况,但我不确定如何最好地实现它 .

更多资源:

2 回答

  • 0

    一般而言,制作可在工作中运行的可管理代码的好方法 - 尤其是也可以在同一窗口中运行的代码(例如,当不支持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索引它们 . 但肯定是可行的,如果你从不同的来源调用工作者函数,也许更好 .

  • 2

    我是问题中提到的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/

    希望这可以帮助,

    --Vadim

相关问题