Mos*_*ouf 6 javascript yield web-worker ecmascript-6
我有一个专用的网络工作人员,在收到启动信号后,它会进入一个长循环,并且根据某些启动设置,该循环将在给定的执行点“屈服”。
这是我的代码的简化版本
var mode = null;
var generator = null;
function* loop() {
for(var i=0;i<10000;i++) {
//Do stuff
for(var j=0;j<10000;j++) {
//Do stuff
if( mode == 'inner' ){
//Yield after each inner loop iteration
yield 2;
}
}
if( mode == 'outer' ){
//Yield after each outer loop iteration
yield 1;
}
}
/*
If mode is not inner or outer the function won't yield
and will process the whole loop in one shot
*/
return null;
}
generator = loop();
self.onmessage = function(event) {
var m = event.data;
if(m.operation == 'run') {
mode = m.mode;
generator.next();
}
if(m.operation == 'pause') {
//Set a flag and check for it in the loop
}
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是允许工作人员按需暂停,问题是在循环中工作人员不会处理消息并且 onmessage 不会被调用,因此我无法发送设置设置的“暂停”消息标志,然后我在循环中检查该标志。
我想做的是让我的函数在每次迭代后让出,以允许工作线程处理消息队列,然后如果没有收到暂停信号则再次恢复该函数,但是,这感觉有点hacky。
有没有办法强制 WebWorker 处理消息队列而不离开循环或产生?或者也许是一种无需通过 onmessage() 即可设置标志的方法?
谢谢
有没有办法强制 WebWorker 处理消息队列而不离开循环或产生?或者也许是一种无需通过 onmessage() 即可设置标志的方法?
没有。Worker 是单线程的,就像主线程一样。一次只能执行一行,幸运的是没有gotos。
另外你的解决方案有一个缺陷,它不会一直使用CPU。s之后,直到您调用消息事件侦听器loop yield后才会继续。.next我建议async/await替代方案:
function Timeout(time) {
return new Promise(resolve=>setTimeout(resolve, time));
}
let mode = "inner";
async function loop() {
for(var i=0;i<10000;i++) {
//Do stuff
for(var j=0;j<10000;j++) {
//Do stuff
if( mode == 'inner' ){
await Timeout(0);
}
}
if( mode == 'outer' ){
await Timeout(0);
}
}
}
// or you can start it only after you receive the right message
const workerLoop = loop();
(async () {
await workerLoop;
self.postMessage("done");
})();
Run Code Online (Sandbox Code Playgroud)
关于暂停,您还可以使用 Promise:
let mode = "inner";
let pausePromise = null;
async function loop() {
for(var i=0;i<1000;i++) {
//Do stuff
for(var j=0;j<1000;j++) {
if(pausePromise) {
console.log("Loop paused");
await pausePromise;
console.log("Loop resumed");
}
}
}
}
let workerLoop = null;
self.onmessage = function(event) {
var m = event.data;
if(m.operation == 'run') {
mode = m.mode;
if(!workerLoop) {
workerLoop = loop();
}
}
if(m.operation == 'pause') {
if(workerLoop) {
var listener = null;
pausePromise = new Promise(resolve=>self.addEventListener("message", listener = (event)=>{
if(event.data.operation=="run") {
console.log("Resuming loop from promise.");
self.removeEventListener("message", listener);
pausePromise = null;
resolve();
}
}))
}
else {
console.warn("Not running!");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这有点脏,但很有效。这是它在 JS 小提琴中的工作:https://jsfiddle.net/Darker/pvy6fszL/16/