简体   繁体   English

由web worker访问dom

[英]Access dom by web worker

I am getting crazy and need your help. 我变得疯狂,需要你的帮助。 I am working on a serviceworker project and I am dealing with a javascript problem. 我正在研究一个serviceworker项目,我正在处理一个javascript问题。 I have two main files. 我有两个主要文件。 The server.html file in which I call the external service-worker.js file in line 52 . 我在其中调用第52行中的外部service-worker.js文件的server.html文件。 Here is my server.html file 这是我的server.html文件

<body>
    <div class="container"> 
        <h1>PRESENTER</h1>
        <div id="nicky">Nickname: <span id="nickname"></span></div>
        <form id="form-nick" name="form-nick" method="post" action="">
            <div class="formelement">
                <label name="labelnick" for="nick">Nickname:</label>
                <input type="text" id="nick" name="nick">
                <button type="submit">OK</button>
            </div>
        </form><br /><br />

        <h1>--></h1><div id="talker"></div>

        <button type="button" class="button blue" id="blue-display" disabled></button><br />

        <button type="button" class="button red" disabled></button><br />

        <button type="button" class="button lightblue" disabled></button>
    </div> <!-- container -->


    <script type="text/javascript">
        $(document).ready(function() {
            console.log("jquery ready function");

            $('#nick').focus();

            $('#form-nick').submit(function(){
                var form = $('#form-nick');
                var data = form.serialize();
                $.post('nicky.php', data, function(response) {
                    if (response) {
                        $('#nicky').show();
                        $('#nickname').text(response);
                        $('#form-nick').hide();
                        $('.blue, .red, .lightblue').fadeIn(100);

                        if('serviceWorker' in navigator){
                            // Register service worker
                            navigator.serviceWorker.register('service-worker.js').then(function(reg){
                                console.log("SW registration succeeded. Scope is "+reg.scope);

                            }).catch(function(err){
                                console.error("SW registration failed with error "+err);
                            });
                        }
                    } else {

                    }
                });
                return false;           
            });       
        });
    </script>
</body>

and here is the service-worker.js file 这是service-worker.js文件

// Install Service Worker
self.addEventListener('install', function(event){
    console.log('>> sw installed!');
});
// Service Worker Active
self.addEventListener('activate', function(event){
    console.log('>> sw activated!');
});
// Service Worker reveives message
self.addEventListener('message', function(event){
    console.log(event.data);
    send_message_to_all_clients(event.data);
    document.getElementById("talker").innerHTML = event.data;
});

In the last line I would like to insert the received message in the div "talker". 在最后一行,我想在div“talker”中插入收到的消息。 But I always get the error service-worker.js:17 Uncaught ReferenceError: document is not defined 但我总是得到错误service-worker.js:17 Uncaught ReferenceError:文档未定义

I took care, that I load the js-File after the document is loaded. 我小心翼翼,我在加载文档后加载了js-File。 Now I don't know what I do wrong. 现在我不知道自己做错了什么。 Thanks. 谢谢。

Service workers — web workers in general — don't have direct access to the DOM at all. 服务工作者 - 一般的Web工作者 - 根本无法直接访问DOM。 Instead, have the worker post the information to the main thread, and have code in the main thread update the DOM as appropriate. 相反,让工作人员将信息发布到主线程,并让主线程中的代码根据需要更新DOM。 The theading model for JavaScript on browsers is that there is only one main UI thread (the default one your in-page code runs on), which can access the DOM. 浏览器上JavaScript的主题模型是只有一个主UI线程(运行页面内代码的默认线程),可以访问DOM。 The others are walled off from it. 其他人被围住了。

This page and this page both talk about messaging between service workers and clients. 此页面此页面都讨论了服务工作者和客户端之间的消息传递。 Here's a really simple example: 这是一个非常简单的例子:

Script in the page loading the service worker: 加载服务工作者的页面中的脚本:

(function() {
    "use strict";

    if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
        console.log("This browser doesn't support service workers");
        return;
    }

    // Listen to messages from service workers.
    navigator.serviceWorker.addEventListener('message', function(event) {
        console.log("Got reply from service worker: " + event.data);
    });

    // Are we being controlled?
    if (navigator.serviceWorker.controller) {
        // Yes, send our controller a message.
        console.log("Sending 'hi' to controller");
        navigator.serviceWorker.controller.postMessage("hi");
    } else {
        // No, register a service worker to control pages like us.
        // Note that it won't control this instance of this page, it only takes effect
        // for pages in its scope loaded *after* it's installed.
        navigator.serviceWorker.register("service-worker.js")
            .then(function(registration) {
                console.log("Service worker registered, scope: " + registration.scope);
                console.log("Refresh the page to talk to it.");
                // If we want to, we might do `location.reload();` so that we'd be controlled by it
            })
            .catch(function(error) {
                console.log("Service worker registration failed: " + error.message);
            });
    }
})();

And in service-worker.js : service-worker.js

self.addEventListener("message", function(event) {
    event.source.postMessage("Responding to " + event.data);
});

That relies on event.source , which is supported by current versions of Chrome and Firefox. 这取决于当前版本的Chrome和Firefox支持的event.source

Alternately, instead of using event.source , you can send a message to multiple clients of a service worker using self.clients.matchAll ; 或者,您可以使用event.source向服务工作者的多个客户端发送消息,而不是使用self.clients.matchAll ; again in service-worker.js : 再次在service-worker.js

self.addEventListener("message", function(event) {
    self.clients.matchAll().then(all => all.forEach(client => {
        client.postMessage("Responding to " + event.data);
    }));
});

matchAll accepts some filtering options . matchAll接受一些过滤选项


You've said you're having trouble getting it to work. 你说你在上班时遇到了麻烦。 Here's a complete version of what's working for me in Chrome and Firefox: 以下是Chrome和Firefox中适合我的完整版本:

service-worker.html : service-worker.html

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Service Worker</title>
</head>
<body>
(Look in the console.)
<script>
(function() {
    "use strict";

    if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
        console.log("This browser doesn't support service workers");
        return;
    }

    // Listen to messages from service workers.
    navigator.serviceWorker.addEventListener('message', function(event) {
        console.log("Got reply from service worker: " + event.data);
    });

    // Are we being controlled?
    if (navigator.serviceWorker.controller) {
        // Yes, send our controller a message.
        console.log("Sending 'hi' to controller");
        navigator.serviceWorker.controller.postMessage("hi");
    } else {
        // No, register a service worker to control pages like us.
        // Note that it won't control this instance of this page, it only takes effect
        // for pages in its scope loaded *after* it's installed.
        navigator.serviceWorker.register("service-worker.js")
            .then(function(registration) {
                console.log("Service worker registered, scope: " + registration.scope);
                console.log("Refresh the page to talk to it.");
                // If we want to, we might do `location.reload();` so that we'd be controlled by it
            })
            .catch(function(error) {
                console.log("Service worker registration failed: " + error.message);
            });
    }
})();
</script>
</body>
</html>

service-worker.js : service-worker.js

self.addEventListener("message", function(event) {
    //event.source.postMessage("Responding to " + event.data);
    self.clients.matchAll().then(all => all.forEach(client => {
        client.postMessage("Responding to " + event.data);
    }));
});

As you can see, that's the version using self.clients.matchAll , with the commented out event.source version above it. 正如你所看到的,这是用的版本self.clients.matchAll ,与注释掉event.source版本上面。

If I run that in two windows, each refresh of each window sends a message to the other windows (because I'm using self.clients.matchAll ...). 如果我在两个窗口中运行它,每个窗口的每次刷新都会向其他窗口发送一条消息(因为我使用的是self.clients.matchAll ...)。

服务工作者基于异步,根据文章,您无法使用服务来访问DOM,以获取更多信息,请访问https://developers.google.com/web/fundamentals/primers/service-workers/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM