我有一个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);
};
答案 0 :(得分:2)
如果您要在前一个呼叫仍在运行时呼叫该工作人员,那么您需要排队或跟踪正在进行的请求。我怀疑除非您需要控制请求队列,否则UI线程更容易触发对工作者的请求,因此浏览器基本上会为您排队请求。
但是你仍然需要跟踪以某种方式发送的请求,所以当你从工作者那里得到一条消息时,你知道它正在响应哪一个。您可以在主线程中执行此操作
工人
主线程
为此,您可以使用以下代码。我只是将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请求,这个方法会允许这样做。