【问题标题】:Where to put eventlisteners for serviceworker在哪里放置 serviceworker 的事件监听器
【发布时间】:2019-01-18 16:38:15
【问题描述】:

基本上,我试图在检测到新的 serviceworker 版本时显示一个对话框,然后让用户决定重新加载以获取它。为此,我们需要在重新加载窗口之前主动设置skipWaiting

这是我的行动:

  onClickHandler = () => {
    console.log('on click', 'posting skipWaiting');
    navigator.serviceWorker.controller.postMessage('skipWaiting');
  };

这是我创建 eventListener 的尝试:

navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        if (installingWorker == null) {
          return;
        }
        installingWorker.onstatechange = () => {
          console.log('worker state', installingWorker.state);
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              console.log(
                'New content is available and will be used when all ' +
                  'tabs for this page are closed.'
              );

              navigator.serviceWorker.addEventListener('message', event => {
                console.log('skip waiting');
                if (event.data === 'skipWaiting') {
                  self.skipWaiting();
                }
              });
            }
          }
        };
      };
    })
    .catch(error => {
      console.error('Error during service worker registration:', error);
    });

问题是navigator.serviceWorker.addEventListener('message', event => 没有被触发。我是在声明监听器错误吗?

【问题讨论】:

  • 您的console.log() 似乎在'tabs for this page are closed. 末尾缺少引号
  • 这是一个错字,我已经更正了

标签: javascript service-worker workbox service-worker-events


【解决方案1】:

你很接近。在您安装的块中,您可以检查

navigator.serviceWorker.controller

如果存在,则意味着旧内容将被清除,新内容将被添加到缓存中。这是显示消息或强制刷新的最佳时机。

  navigator.serviceWorker.register('service-worker.js').then(function (registration) {

                    $log.debug('The service worker has been registered ', registration);

                    if(navigator.online) {
                        toastr.warning('Offline Mode', 'Application Status');
                    }

                    // updatefound is fired if service-worker.js changes.
                    registration.onupdatefound = function () {
                        // The updatefound event implies that reg.installing is set; see
                        // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
                        var installingWorker = registration.installing;

                        installingWorker.onstatechange = function () {
                            switch (installingWorker.state) {
                                case 'installed':
                                    if (navigator.serviceWorker.controller) {
                                        // At this point, the old content will have been purged and the fresh content will
                                        // have been added to the cache.
                                        // It's the perfect time to display a "New content is available; please refresh."
                                        // message in the page's interface.
                                        toastr.info('Application has been updated, please refresh this page for the most recent version');

                                        window.location.reload();

                                        });
                                        caches.delete('scope-dynamic').then(function () {
                                            $log.debug('Killed the dynamic cache!');
                                        })
                                        $log.debug('New or updated content is available.');
                                    } else {
                                        // At this point, everything has been precached.
                                        // It's the perfect time to display a "Content is cached for offline use." message.
                                        toastr.success('Content is cached for offline use.', 'Application Status');
                                        $log.debug('Content is now available offline!');
                                    }
                                    break;

                                case 'redundant':
                                    $log.error('The installing service worker became redundant.');
                                    break;

                            }
                        };
                    };
                }).catch(function (e) {
                    $log.error('Error during service worker registration:', e);
                });

那里散布了一些棱角分明的东西,但这应该可以帮助您到达想要的位置。

【讨论】:

    【解决方案2】:

    这里的问题是你提供的代码只定义了从你的客户端接收和发送消息到服务工作者。

    下面的方法定义了一条消息要发送给你的控制器(活动)服务工作者。

    onClickHandler = () => {
        console.log('on click', 'posting skipWaiting');
        navigator.serviceWorker.controller.postMessage('skipWaiting');
    };
    

    下面的定义在您的 ServiceWorker 容器上添加了一个事件侦听器,以接收从 Service Worker 发送的任何消息。

    navigator.serviceWorker.addEventListener('message', event => {
        console.log('skip waiting');
        if (event.data === 'skipWaiting') {
            self.skipWaiting();
        }
    });
    

    您现在需要从 service worker 文件中定义事件处理程序来接收和发送消息。

    在 service worker 文件中,接收来自客户端的消息:

    self.addEventListener('message', function handler (event) {
       console.log('skip waiting');
       if (event.data === 'skipWaiting') {
          self.skipWaiting();
       }
    });
    

    从 serviceworker 向您的客户端发送消息:

    self.addEventListener('fetch', function(event) {
      self.clients.matchAll().then(all => all.map(client => client.postMessage('data from webworker')));
    });
    

    您还可以使用 MessageChannel 从 serviceworker 发回数据。在您的客户端上,您必须定义如下内容:

        navigator.serviceWorker
            .register(swUrl)
            .then(registration => {
                var messageChannel = new MessageChannel();
                // listener for messages from the ServiceWorker    
                messageChannel.port1.addEventListener('message', (event) => console.log(event.data)); 
    
                function sendMessage (message) {
                    //send message to the active service worker
                    navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
                }
          onClickHandler = () => {
              sendMessage('skipWaiting');
          };
       });
    

    我发现下面的文章很有帮助。

    ServiceWorker, MessageChannel & postMessage by Nicolás Bevacqua

    【讨论】:

    • 是否可以在JS主线程中监听message事件?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 2019-07-14
    相关资源
    最近更新 更多