【问题标题】:postMessage is executed too late in codepostMessage 在代码中执行得太晚
【发布时间】:2016-09-16 06:19:08
【问题描述】:

我正在使用 postMessage 为 JScript 中的工作人员调用参数。

不幸的是,似乎 postMessage 是在 DOM 的主线程空闲后执行的。我需要一个函数来在我的代码运行时发布。

背景:Worker 持有 webSocket 与服务器通信。

function xy() {
   flag = 0;   

   while (!flag) {

      WORKER.postMessage(flag);

      //Problem: WORKER does not get post; Posts are invoked after while
      //Need something to break the rules
      GiveWorkerExecutionTimeOrDoEventsAndMessageStack();

      flag := CheckFlag();
   }
}

感谢您的帮助:)!

编辑:

我会尽量解释清楚:

首先我有一个工人拿着一个网络套接字(单独的 js 文件):

var wsUri = "ws://localhost:8002/chat"; 

var websocket;

"use strict";

self.addEventListener('message', function (e) {
    switch (e.data[0]) {
        case "run":
            runWebSocket();
            break;
        case "send":
            websocket.send(e.data[1]);
            break;
        case "addWait":
            break;
    }
}, false);

function runWebSocket() { 
    websocket = new WebSocket(wsUri);
    websocket.binaryType = "arraybuffer"; 
    websocket.onopen = function (evt) { onOpen(evt) };
    websocket.onclose = function(evt) { onClose(evt) }; 
    websocket.onmessage = function(evt) { onMessage(evt) }; 
    websocket.onerror = function(evt) { onError(evt) }; 
}

function onOpen(evt) { 
    self.postMessage(['open', '']);
}

function onClose(evt) { 
    self.postMessage(['close', '']);
}

function onMessage(evt) {
    self.postMessage(['arrival', evt.data]);
} 

function onError(evt) { 
    self.postMessage(['error', evt.data]);
} 

function doSend(message) { 
    websocket.send(message); 
} 

这个 Worker 运行在一个简单的测试环境中,它有一个按钮和一个等待点击事件的监听器。

如果

a) 点击数据块的发送完成 b) 代码正在等待接收服务器的应答,点击被处理。我只想在这种情况下释放按钮

所以我用这种方式制作了按钮点击监听器(见函数EventCallback):

一开始我创建了一个等待键,它将存储在一个 Map 中。只要地图包含我的等待键,就不会提交点击。

发布点击内容后,我有我的等待循环。它应该在我的工作人员发送答案时等待,应该提交处理。

现在我告诉你我的问题清单:

1) 即使在等待循环之前有一个 post 到 worker(点击事件数据),消息也永远不会到达 worker。工人在结束循环后得到帖子。

2) 我不确定,我的来自服务器的检查答案会发生什么,它必须发布到主线程。我开始尝试使用 setTimeout,但如果没有帖子返回到我的主线程,这是无稽之谈。

函数事件回调(evtName){ var WaitingKey;

evtName.stopPropagation();

WaitingThreadCtr++;
WaitingKey = "#" + WaitingThreadCtr;
WaitingThreads.set(WaitingKey, WaitingKey);

var doc = document.implementation.createDocument(null, "controlevent", null);

// create the <submitter>, <name>, and text node
var submitterElement = doc.createElement("command");
var submitterData = doc.createElement("data");

Att = document.createAttribute("id");
Att.nodeValue = 'controlEvent';
submitterElement.attributes.setNamedItem(Att);

Att = document.createAttribute("threadid");
Att.nodeValue = WaitingKey;
submitterElement.attributes.setNamedItem(Att);

for (var p in evtName) {
    Att = document.createAttribute(p);
    Att.nodeValue = evtName[p];
    submitterData.attributes.setNamedItem(Att);
}

submitterElement.appendChild(submitterData);
doc.documentElement.appendChild(submitterElement);

doSend(doc.documentElement.innerHTML);

flag = false;
do {
    window.setTimeout(DoInterrupt, 100);
    if (WaitingThreads.get(WaitingKey) != WaitingKey) flag = true;
} while (flag == false);

}

这只是一个简单的示例,因为我想在我的代码中的其他地方创建这个数据协议来模拟使用 ByRef 参数的函数调用。

<!DOCTYPE html> 
<meta charset="utf-8" /> 

<script language="javascript" type="text/javascript"> 

var wsUri = "ws://localhost:8002/chat"; 

var webSocketWorker;

var output, outputW, outputH;
var WaitingThreads;
var WaitingThreadCtr;
var Timer;
var Interval;

"use strict";

function init() {
    output = document.getElementById("output");

    WaitingThreads = new Map();
    WaitingThreadCtr = 0;

    webSocketWorker = new Worker("websocket.js");

    webSocketWorker.addEventListener('message', WebSocketServerListen, false);

    webSocketWorker.postMessage(['run', '']);
}

function WebSocketServerListen(e) {
    switch (e.data[0]) {
        case 'arrival':
            dataArrival(e.data[1]);
            break;
        case 'error':
            break;
        case 'open':
            break;
        case 'close':
            break;
    }
}

function doSend(message) {
    webSocketWorker.postMessage(['send', message]);
}

function dataArrival(data) {

    var i, k, m, parser, xmlDoc, NodeCommand, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl;

    parser = new DOMParser();
    xmlDoc = parser.parseFromString(data, "text/xml");

    NodeCommand = xmlDoc.getElementsByTagName("command");

    //DOM ist nun verfügbar
    for (i = 0; i < NodeCommand.length; i++) {
        switch (NodeCommand[i].childNodes[0].textContent) {
            case "event":
                id = NodeCommand[i].attributes.getNamedItem("threadid").value;
                WaitingThreads.delete(id);
                break;
            case "addControl":
                //Tag einlesen; tag hat die Attribute id und html
                CommandAddControl(NodeCommand[i]);
                break;
            case "addDiv":
                //Tag einlesen; tag hat die Attribute id und html
                CommandAddDiv(NodeCommand[i]);
                break;
            case "hideControl":
                //Tag einlesen; tag hat die Attribute id und html
                CommandShowHideControl(NodeCommand[i], false);
                break;
            case "showControl":
                //Tag einlesen; tag hat die Attribute id und html
                CommandShowHideControl(NodeCommand[i], true);
                break;
            case "resizeControl":
                //Tag einlesen; tag hat die Attribute id und html
                CommandResizeControl(NodeCommand[i]);
                break;
            case "setStyle":
                //Tag einlesen; tag hat die Attribute id und html
                CommandSetStyle(NodeCommand[i]);
                break;
            case "setProperty":
                //Tag einlesen; tag hat die Attribute id und html
                CommandSetProperty(NodeCommand[i]);
                break;
        }
    }
}

function CommandAddDiv(CommandNode) {
    var k, m, e, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {

        if (Tag[k].childNodes[0]) {
            El = Tag[k].childNodes[0].textContent;
        }

        id = Tag[k].attributes.getNamedItem("id").value;

        DivEl = document.getElementById(id);
        if (DivEl) DivEl.parentNode.removeChild(DivEl);

        //div anlegen
        DivEl = document.createElement("div");
        DivEl.Control = new Control();

        Att = document.createAttribute("id");
        Att.nodeValue = id;
        DivEl.attributes.setNamedItem(Att);

        Att = document.createAttribute("class");
        Att.nodeValue = Tag[k].attributes.getNamedItem("class").value;
        DivEl.attributes.setNamedItem(Att);

        Att = document.createAttribute("style");
        Att.nodeValue = Tag[k].attributes.getNamedItem("style").value;
        DivEl.attributes.setNamedItem(Att);

        if (Tag[k].attributes.getNamedItem("visible").value == "0") {
            DivEl.style.display = "none";
        }

        El = Tag[k].getElementsByTagName("evt");
        for (e = 0; e < El.length; e++) {
            //Events binden
            DivEl.addEventListener(El[e].attributes.getNamedItem("name").value, EventCallback, false);
        }

        //append to id dest
        Dest = Tag[k].attributes.getNamedItem("dest").value;
        if (Dest == '<root>') {
            output.appendChild(DivEl);
        } else {
            DivDest = document.getElementById(Dest);
            DivDest.appendChild(DivEl);
        }
    }
}

function Control() {
    this.AlignLeft = 0;
    this.AlignRight = 0;
    this.AlignTop = 0;
    this.AlignBottom = 0;
}

function CommandAddControl(CommandNode) {
    var k, m, e, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {

        if (Tag[k].childNodes[0]) {
            El = Tag[k].childNodes[0].textContent;
        }

        id = Tag[k].attributes.getNamedItem("id").value;

        DivEl = document.getElementById(id);
        if (DivEl) DivEl.parentNode.removeChild(DivEl);

        //div anlegen
        DivEl = document.createElement("div");

        Att = document.createAttribute("id");
        Att.nodeValue = id;
        DivEl.attributes.setNamedItem(Att);

        Att = document.createAttribute("style");
        Att.nodeValue = Tag[k].attributes.getNamedItem("style").value;
        DivEl.attributes.setNamedItem(Att);

        TagEl = document.createElement(El);
        TagEl.textContent = Tag[k].attributes.getNamedItem("html").value;

        //Tag-Node kann Att-Knoten haben
        NAtt = Tag[k].getElementsByTagName("att");

        for (m = 0; m < NAtt.length; m++) {
            Att = document.createAttribute(NAtt[m].attributes.getNamedItem("name").value);
            Att.nodeValue = NAtt[m].attributes.getNamedItem("value").value;
            TagEl.attributes.setNamedItem(Att);
        }
        DivEl.appendChild(TagEl);

        //Events binden
        El = Tag[k].getElementsByTagName("evt");
        for (e = 0; e < El.length; e++) {
            //Events binden
            TagEl.addEventListener(El[e].attributes.getNamedItem("name").value, EventCallback, false);
        }

        //append to id dest
        Dest = Tag[k].attributes.getNamedItem("dest").value;
        if (Dest == '<root>') {
            output.appendChild(DivEl);
        } else {
            DivDest = document.getElementById(Dest);
            DivDest.appendChild(DivEl);
        }
    }
}

function CommandShowHideControl(CommandNode, ShowHide) {
    var k, m, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {
        id = Tag[k].attributes.getNamedItem("id").value;

        El = document.getElementById(id);
        if (El) {
            if (ShowHide == false) {
                El.style.display = "none";
            } else {
                El.style.display = "block";
            }
        }
    }
}

function CommandResizeControl(CommandNode) {
    var k, m, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {
        id = Tag[k].attributes.getNamedItem("id").value;

        El = document.getElementById(id);
        if (El) {
            El.style.left = Tag[k].attributes.getNamedItem("left").value;
            El.style.top = Tag[k].attributes.getNamedItem("top").value;
            El.style.width = Tag[k].attributes.getNamedItem("width").value;
            El.style.height = Tag[k].attributes.getNamedItem("height").value;
        }
    }
}

function CommandSetStyle(CommandNode) {
    var k, m, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {
        id = Tag[k].attributes.getNamedItem("id").value;

        El = document.getElementById(id);
        if (El) {
            El.style = Tag[k].attributes.getNamedItem("style").value;
        }
    }
}

function CommandSetProperty(CommandNode) {
    var k, m, Tag, Att, El, id, htm, NAtt;
    var DivEl, DivStyle, TagEl, Dest, DivDest;

    Tag = CommandNode.getElementsByTagName("tag");

    for (k = 0; k < Tag.length; k++) {
        id = Tag[k].attributes.getNamedItem("id").value;

        El = document.getElementById(id);
        if (El) {
            eval("El." + Tag[k].attributes.getNamedItem("property").value + " = " + Tag[k].attributes.getNamedItem("value").value);
        }
    }
}

function TimeoutFunc() {
    //Timer = setTimeout(TimeoutFunc, 50);
}

function WaitInterval() {
    Timer = setTimeout(TimeoutFunc, 10);
}

function EventCallback(evtName) {
    var WaitingKey;

    evtName.stopPropagation();

    WaitingThreadCtr++;
    WaitingKey = "#" + WaitingThreadCtr;
    WaitingThreads.set(WaitingKey, WaitingKey);

    var doc = document.implementation.createDocument(null, "controlevent", null);

    // create the <submitter>, <name>, and text node
    var submitterElement = doc.createElement("command");
    var submitterData = doc.createElement("data");

    Att = document.createAttribute("id");
    Att.nodeValue = 'controlEvent';
    submitterElement.attributes.setNamedItem(Att);

    Att = document.createAttribute("threadid");
    Att.nodeValue = WaitingKey;
    submitterElement.attributes.setNamedItem(Att);

    for (var p in evtName) {
        Att = document.createAttribute(p);
        Att.nodeValue = evtName[p];
        submitterData.attributes.setNamedItem(Att);
    }

    submitterElement.appendChild(submitterData);
    doc.documentElement.appendChild(submitterElement);

    doSend(doc.documentElement.innerHTML);
    
    flag = false;
    do {
        window.setTimeout(DoInterrupt, 100);
        if (WaitingThreads.get(WaitingKey) != WaitingKey) flag = true;
    } while (flag == false);
}

function DoInterrupt() {
    
}

function WindowResize(evtName) {
    var w, h;
    w = output.clientWidth;
    h = output.clientHeight;
    
    if ((outputW != w) || (outputH != h)) {

        outputW = w;
        outputH = h;

        var Att;
        var doc = document.implementation.createDocument(null, "windowResize", null);

        // create the <submitter>, <name>, and text node
        var submitterElement = doc.createElement("command");
        Att = document.createAttribute("id");
        Att.nodeValue = 'windowResize';
        submitterElement.attributes.setNamedItem(Att);

        Att = document.createAttribute("width");
        Att.nodeValue = w;
        submitterElement.attributes.setNamedItem(Att);

        Att = document.createAttribute("height");
        Att.nodeValue = h;
        submitterElement.attributes.setNamedItem(Att);

        doc.documentElement.appendChild(submitterElement);

        doSend(doc.documentElement.innerHTML);

    }
}

function writeToScreen(message) { 
    var pre = document.createElement("p"); 
    pre.style.wordWrap = "break-word"; 
    pre.innerHTML = message; 
    output.appendChild(pre); 
} 

window.addEventListener("load", init, false); 
window.addEventListener("resize", WindowResize, false);

</script> 

<link rel="stylesheet" href="w3.css">
<html>

<head>
<title>WebSocket Test</title> 
</head>

<body>
<h2>WebSocket Test</h2> 

<div id="output"></div> 

</body>
</html>

【问题讨论】:

  • 您能否提供更多信息以及您如何在主线程中接收消息
  • 我能告诉你的是,这可以在普通的 javascript 中工作。我刚刚测试过...

标签: web-worker postmessage


【解决方案1】:

由于我一直在研究多线程 js api (OODK-JS),我可以回答这个问题:

不可能通过异步调用(包括 setTimout)打破无限循环,因为回调函数仅在线程免费时执行。运行一个无限循环独占线程,所有异步回调都被延迟,直到循环完成,从未发生过

flag = false;
do {
    // DoInterrupt is never called as the do/while loop is monopolizing the current thread 
    window.setTimeout(DoInterrupt, 100);
    if (WaitingThreads.get(WaitingKey) != WaitingKey) flag = true;
} while (flag == false);

【讨论】:

    猜你喜欢
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 2016-08-20
    • 2012-05-17
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多