Webworker return 回调后的结果
Webworker return result after callback
我有一个 Angular 服务,我将 $q
服务与网络工作者结合使用。在我使用 webworkers 之前的原始函数中,我的 completeClass
函数将 return 一个对象。
我将代码替换为 post 一条消息到我的新网络工作者脚本。
Webworker 的回调在我添加事件监听器的 initWorkers
函数中。
我的目标是 completeClass
函数 return 是 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);
};
如果您要在上一个调用仍在 运行 时调用工作人员,那么您需要一些东西来排队或跟踪正在进行的请求。我的怀疑是,除非您需要控制请求队列,否则 UI 线程向 worker 发出请求会更简单,因此浏览器基本上会为您排队请求。
但是您仍然需要跟踪以某种方式发送的请求,因此当您从工作人员那里收到一条消息时,您知道它正在响应哪个请求。您可以通过在主线程中执行此操作
- 为每个请求生成一个唯一的 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];
}
};
});
然后在 worker 中你可以有这样的代码:
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);
};
My goal is that the completeClass function returns the result of the webworker. How can I make this happen?
说明一下,不能直接return结果,因为结果是异步计算的,所有的函数调用都必须return同步。但它可以 return 一个稍后解析为结果的承诺,就像 $http
所做的那样。要使用上面的内容,您可以执行类似
app.controller('MyController', function($scope, AutoComplete) {
$scope.complete = function(text) {
AutoComplete.completeClass(text).then(function(result) {
// Do something with result
});
});
});
注意:从技术上讲,如果 worker 对一个请求同步完成所有工作,则没有必要将 ID 与每个请求一起传递,因此按收到的顺序响应每个调用。在上面的示例中,主线程始终可以假定对工作线程的调用构成一个先进先出队列。但是,传递 ID 可以让工作人员灵活地不按收到的订单完成工作。比如说在以后的版本中它需要做一些异步的事情,比如调用另一个工作人员,或者发出一个 ajax 请求,这个方法将允许这样做。
我有一个 Angular 服务,我将 $q
服务与网络工作者结合使用。在我使用 webworkers 之前的原始函数中,我的 completeClass
函数将 return 一个对象。
我将代码替换为 post 一条消息到我的新网络工作者脚本。
Webworker 的回调在我添加事件监听器的 initWorkers
函数中。
我的目标是 completeClass
函数 return 是 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);
};
如果您要在上一个调用仍在 运行 时调用工作人员,那么您需要一些东西来排队或跟踪正在进行的请求。我的怀疑是,除非您需要控制请求队列,否则 UI 线程向 worker 发出请求会更简单,因此浏览器基本上会为您排队请求。
但是您仍然需要跟踪以某种方式发送的请求,因此当您从工作人员那里收到一条消息时,您知道它正在响应哪个请求。您可以通过在主线程中执行此操作
- 为每个请求生成一个唯一的 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];
}
};
});
然后在 worker 中你可以有这样的代码:
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);
};
My goal is that the completeClass function returns the result of the webworker. How can I make this happen?
说明一下,不能直接return结果,因为结果是异步计算的,所有的函数调用都必须return同步。但它可以 return 一个稍后解析为结果的承诺,就像 $http
所做的那样。要使用上面的内容,您可以执行类似
app.controller('MyController', function($scope, AutoComplete) {
$scope.complete = function(text) {
AutoComplete.completeClass(text).then(function(result) {
// Do something with result
});
});
});
注意:从技术上讲,如果 worker 对一个请求同步完成所有工作,则没有必要将 ID 与每个请求一起传递,因此按收到的顺序响应每个调用。在上面的示例中,主线程始终可以假定对工作线程的调用构成一个先进先出队列。但是,传递 ID 可以让工作人员灵活地不按收到的订单完成工作。比如说在以后的版本中它需要做一些异步的事情,比如调用另一个工作人员,或者发出一个 ajax 请求,这个方法将允许这样做。