2016-08-08 4 views

Antwort

28

Im Allgemeinen wird Code, der sich außerhalb eines beliebigen Ereignishandlers in der "obersten Ebene" des globalen Bereichs des Service-Arbeiters befindet, jedes Mal ausgeführt, wenn der Service-Worker-Thread (/ Prozess) gestartet wird. Der Service-Worker-Thread kann zu beliebigen Zeiten starten (und anhalten) und ist nicht an die Lebensdauer der von ihm gesteuerten Webseiten gebunden.

(Das Starten/Stoppen des Service-Worker-Threads ist häufig eine Leistungs-/Akkuoptimierung und stellt sicher, dass z. B. nur durch das Navigieren zu einer Seite, die einen Service-Mitarbeiter registriert hat, kein zusätzlicher Leerlauf-Thread generiert wird im Hintergrund.)

Die Kehrseite davon ist, dass jedes Mal, wenn der Service-Worker-Thread angehalten wird, ein vorhandener globaler Status zerstört wird. Sie können zwar bestimmte Optimierungen vornehmen, beispielsweise eine geöffnete IndexedDB-Verbindung im globalen Status speichern, in der Hoffnung, sie für mehrere Ereignisse freizugeben, müssen jedoch bereit sein, sie neu zu initialisieren, wenn der Thread zwischen den Ereignishandleraufrufen beendet wurde.

Eng verwandt mit dieser Frage ist ein Missverständnis, das ich über den install Event-Handler gesehen habe. Ich habe gesehen, dass einige Entwickler den Handler install verwenden, um den globalen Zustand zu initialisieren, auf den sie sich dann in anderen Event-Handlern wie fetch verlassen. Dies ist gefährlich und wird wahrscheinlich zu Fehlern in der Produktion führen. Der install-Handler wird einmal pro Version eines Service-Arbeiters ausgelöst und wird normalerweise am besten für Aufgaben verwendet, die an die Versionsverwaltung von Service-Arbeitern gebunden sind, wie das Zwischenspeichern neuer oder aktualisierter Ressourcen, die von dieser Version benötigt werden. Nachdem der Handler install erfolgreich abgeschlossen wurde, wird eine bestimmte Version eines Service Worker als "installiert" betrachtet, und der Handler install wird nicht erneut ausgelöst, wenn der Service Worker zum Beispiel ein fetch oder message Event startet.

Wenn also ein globaler Status vor der Verarbeitung initialisiert werden muss, z. B. ein fetch-Ereignis, können Sie dies im globalen Service-Manager-Bereich auf oberster Ebene tun (optional auf ein Verspre- chen innerhalb der fetch warten) Event-Handler, um sicherzustellen, dass alle asynchronen Operationen abgeschlossen sind). Do nicht verlassen Sie sich auf den install Handler, um globalen Bereich einzurichten!

Hier ist ein Beispiel, dass einige dieser Punkte zeigt:

// Assume this code lives in service-worker.js 

// This is top-level code, outside of an event handler. 
// You can use it to manage global state. 

// _db will cache an open IndexedDB connection. 
let _db; 
const dbPromise =() => { 
    if (_db) { 
    return Promise.resolve(_db); 
    } 

    // Assume we're using some Promise-friendly IndexedDB wrapper. 
    // E.g., https://www.npmjs.com/package/idb 
    return idb.open('my-db', 1, upgradeDB => { 
    return upgradeDB.createObjectStore('key-val'); 
    }).then(db => { 
    _db = db; 
    return db; 
    }); 
}; 

self.addEventListener('install', event => { 
    // `install` is fired once per version of service-worker.js. 
    // Do **not** use it to manage global state! 
    // You can use it to, e.g., cache resources using the Cache Storage API. 
}); 

self.addEventListener('fetch', event => { 
    event.respondWith(
    // Wait on dbPromise to resolve. If _db is already set, because the 
    // service worker hasn't been killed in between event handlers, the promise 
    // will resolve right away and the open connection will be reused. 
    // Otherwise, if the global state was reset, then a new IndexedDB 
    // connection will be opened. 
    dbPromise().then(db => { 
     // Do something with IndexedDB, and eventually return a `Response`. 
    }); 
); 
}); 
+1

Das ist sehr hilfreich, danke! –

Verwandte Themen