回调后Webworker返回结果

时间:2015-11-04 13:52:09

标签: javascript angularjs asynchronous promise web-worker

我有一个Angular服务,我将$q服务与webworkers结合使用。在使用webworkers之前的原始函数中,我的completeClass函数将返回一个对象。

我替换了代码,将消息发布到我的新Web worker脚本。 webworker的回调在我的initWorkers函数中,我在其中添加了eventlistener。

我的目标是completeClass函数返回webworker的结果。我怎样才能做到这一点?

this.classWorker = new Worker('app/shared/autocomplete/autocomplete-class-worker.js');

this.completeClass = function(text){
    var self = this;    
    var defer = $q.defer();
    classWorker.postMessage([text, this.oldText, this.oldProposals, this.aliases, this.entityClasses])
};

this.initWorkers = function(){
    var self = this;
    worker.addEventListener('message', function(e) {
        defer.resolve(e.data);
        self.oldProposals = e.data[1];
        self.oldText = text;
        return e.data[0];
    }, false);
};

1 个答案:

答案 0 :(得分:2)

如果您要在前一个呼叫仍在运行时呼叫该工作人员,那么您需要排队或跟踪正在进行的请求。我怀疑除非您需要控制请求队列,否则UI线程更容易触发对工作者的请求,因此浏览器基本上会为您排队请求。

但是你仍然需要跟踪以某种方式发送的请求,所以当你从工作者那里得到一条消息时,你知道它正在响应哪一个。您可以在主线程中执行此操作

  • 为每个请求生成唯一ID。对于很多情况,不断增加的整数就足够了。
  • 创建与ID
  • 关联的延迟对象并存储它
  • 将请求发送给工作人员,传递ID
  • 将延期对象的承诺传递回调用者

工人

  • 收到ID
  • 的消息
  • 它的'工作
  • 将结果与ID
  • 一起发回

主线程

  • 收到包含工作ID和结果的消息。
  • 按ID检索延迟对象,并使用工作结果对其进行解析。

为此,您可以使用以下代码。我只是将text传递给了工作人员,让completeText回复,从而略微简化了您的案例。您可以在实际案例中添加更多信息。

app.service('AutoComplete', function($q) {
  var id = 0;
  var worker = new Worker('app/shared/autocomplete/autocomplete-class-worker.js');
  var inProgress = {};

  this.completeClass = function(text) {
    var deferred = $q.defer();
    id++;
    var request = {
      id: id,
      text: text
    };
    inProgress[id] = deferred;
    worker.postMessage(request);
    return deferred.promise;
  };

  worker.onmessage = function(e) {
    var response = e.data;
    var id = response.id;
    var type = response.type; // resolve, reject, or notify
    var completeText = response.completeText;
    inProgress[id][type](completeText);
    if (type === 'resolve' || type === 'reject') {
      delete inProgress[id];
    }
  };
});

然后在工人中你可以得到如下代码:

self.onmessage = function(e) {
  var request = e.data;
  var text = request.text;
  var id = request.id;

  // Do the work here
  var completeText = ...

  var response = {
    id: id,
    type: 'resolve', // Can reject the promise in the main thread if desired
    completeText: completeText
  };

  self.postMessage(response);
};
  

我的目标是completeClass函数返回webworker的结果。我怎样才能做到这一点?

为了澄清,它不能直接返回结果,因为结果是异步计算的,并且所有函数调用必须同步返回。但它可以返回一个后来解析为结果的承诺,就像$http那样。要使用上述内容,您可以执行类似

的操作
app.controller('MyController', function($scope, AutoComplete) {
   $scope.complete = function(text) {
     AutoComplete.completeClass(text).then(function(result) {
       // Do something with result
     });
   });
});

注意:从技术上讲,如果工作人员在一个请求上同步完成所有“工作”,则不需要传递ID和每个请求,因此会按照收到的顺序响应每个呼叫。在上面的示例中,主线程始终可以假定对worker的调用构成先进先出队列。但是,传递ID可以使工人无法按照收到的顺序完成工作。比如说在以后的版本中它需要做一些异步操作,比如调用另一个worker,或者发一个ajax请求,这个方法会允许这样做。