Worker

My Goal

WORKER, OMG WOW

Content

 

  1. Web Worker            (now)
  2. Shared Worker       (soon)
  3. Service Worker (far far away)

Worker

Reason

  • Run a task without blocking the current thread
  • That's it
  • Support: 93%

Demo time

(sponsored by D1)

How to start

if (window.Worker) {
    var myWorker = new Worker('worker.js');
} else {
    // :(
}

also possible inline via type="text/js-worker"

How to interact

myWorker.postMessage(['your','fancy', 'workload']);

myWorker.onmessage = function(e) {
  console.log('Message received from worker', e.data);
}

myWorker.terminate(); // No cleanup at worker

How to worker

importScripts('foo.js'); // import lib
onmessage = function(e) {
  var workerResult = 
    'Result: ' + 
    e.data[0] + 
    e.data[1] + 
    'Result';
  console.log('Posting message back to main script');
  postMessage(workerResult);
  close(); // Terminate process gracefully
}

Shared Worker

What's better?

  • Shares context with multiple windows / iframes
  • heavy init works can be done only once
  • Communication differs to normal worker
  • support: 56%

Demo time!

worker.js

var clients = [];
 
var broadcast = function(clients, message) {..clients[i].postMessage(message);..}
 
self.addEventListener("connect", function (e) {
    var port = e.ports[0];
 
    clients.push(port);
    port.addEventListener("message", function (e) {
      var data = e.data;
      broadcast(clients, {"id": e.data.id, "said": e.data.message});
    })
    port.start();
    broadcast(clients, {"id":clients.length, "cmd": "connected"});
 
}, false);

page.js

var worker = new SharedWorker("./sharedWorker.js");
var id = null;
worker.port.addEventListener("message", function(e) {
  console.log('worker id is', id)
  if (e.data.cmd === 'connected' && !(id != null)) {
    id = e.data.id;
  } else {
    $('#chat-window').append('<div>' + JSON.stringify(e.data) + '</div>');
  }
});
worker.port.start();
$('#dialog-form').on('submit', function(e){
    ...
    worker.port.postMessage({message: message, id: id});
});

Service Worker

Service Worker

Why is it awesome?

  • it lives in a context above the page
  • it can intercept with network requests
  • it has it's own cache
  • it has it's own lifecycle
  • it can be scoped

Lifecycle

Where can I look into the internals?

Registration

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function() {
    // Registration was successful
    console.log('ServiceWorker registration successful');
  }).catch(function() {
    // registration failed :(
    console.log('ServiceWorker registration failed');
  });
}

But how do I update a service worker?

Change the File ==> Phased Restart 

  • background loading and diff checking
  • install event will be fired on new one
  • current one on waiting state
  • kill old service worker instances on window close

Installation

var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];

self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

Fetch

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }

        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

Fetch

            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});

Activate

self.addEventListener('activate', function(event) {

  var cacheWhitelist = ['pages-cache-v1', 'blog-posts-cache-v1'];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Let's talk about the scope

  • /
    • /mobile
      • /posts
      • /events
    • /frontend
      • /posts
      • /events

Let's talk about the scope

  • /
    • /mobile
      • /posts
      • /events
    • /frontend
      • /posts
      • /events
navigator.serviceWorker.register('serviceWorker.js')

Let's talk about the scope

  • /
    • /mobile
      • /posts
      • /events
    • /frontend
      • /posts
      • /events
navigator.serviceWorker.register('serviceWorker.js')

Let's talk about the scope

  • /
    • /mobile
      • /posts
      • /events
    • /frontend
      • /posts
      • /events
navigator.serviceWorker.register('serviceWorker.js', {
  scope: '/frontend'
})

Cache API 

  • on Cache Storage
    • match, open
    • has, keys
    • delete
  • on Cache
    • match(All), add(All)
    • put, delete, keys

(Returns promises) - polyfill here

Downsides

Current Status

Planned Features

Demo time

Worker

By Daniel Schmidt

Worker

Welcome to the land of awesomness :)

  • 1,107