React工程化之PWA之serviceWorker


我們使用create-react-app腳手架時,會發現入口文件index.js中有這樣一個引入使用。

 

這個文件可以視情況用或者不用,它是用來做離線緩存等任務的,實際上就是為react項目注冊了一個service worker。這樣的話,如果在線上,只要訪問過一次該網站,以后即使沒有網絡也可以訪問(此時使用的是之前緩存的資源)。只在生產環境中有效(process.env.NODE_ENV === ‘production’)

在項目的public目錄下,會有一個manifest.json文件,可以在這里做一些配置(圖標、名字等等)。當用戶把網頁生成一個快捷方式時。會感覺用起來像原生APP一樣。

源碼分析

接下來我們來分析一下源碼:看看其實現原理,代碼很少也就100多行。該文件主要導出兩個方法:

register():注冊

register方法是默認(default)的導出方法。

export default function register() { //當前環境是生產環境並且瀏覽器支持serverWorker // The URL constructor is available in all browsers that support SW. if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { //返回一個新的URL,作為生成靜態文件夾的路徑,下面說明... const publicUrl = new URL(process.env.PUBLIC_URL, window.location); //如果靜態文件和當前環境不在同一個域,注冊沒有意義,那就直接返回。 if (publicUrl.origin !== window.location.origin) { return; } window.addEventListener('load', () => { //頁面加載完成執行以下代碼.... const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // 如果是本地環境,調用checkValidServiceWorker進行注冊 checkValidServiceWorker(swUrl); // 注冊成功后,打印信息 navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + 'worker. To learn more, visit https://goo.gl/SC7cgQ' ); }); } else { // 如果不是本地環境(已經暴露在外網)僅僅只注冊 service worker registerValidSW(swUrl); } }); } } 

new URL(process.env.PUBLIC_URL, window.location),如果第一個參數是絕對路徑,第二個參數忽略。如果第一個參數是相對路徑,就會把第一個參數拼接到第二個參數后面。這里第一個參數是public目錄的絕對路徑。

unregister():取消注冊
export function unregister() { //如果支持serviceWorker,並且處於就緒狀態,那么調用其提供的取消注冊方法 if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(registration => { registration.unregister(); }); } } 

補充:

一個文件中可以用多個export方法,但是只能有一個export default 方法。在使用import導入的時候,可以為export default導出的方法隨意起名字且不用使用{}。普通導出的方法則反之,只能用{}並且使用導出時的名字。(可以這樣說,用{}就必須使用導出時的名字)

如果按以下寫法也是可以的,因為可以隨意取名字。

import haha from './registerServiceWorker'; haha(); 

如果想使用普通導出方法,就需要加上{}了,而且名字必須和導出時的名字一樣。

import {unregister} from './registerServiceWorker'; unregister(); 

然后就是一些內部方法了,在上面的方法中有調用:

isLocalhost:判斷是不是本地環境

這其實是一個布爾值,通過匹配當前地址段判斷當前是不是本地環境。

const isLocalhost = Boolean( window.location.hostname === 'localhost' || // [::1] is the IPv6 localhost address. window.location.hostname === '[::1]' || // 127.0.0.1/8 is considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ ) ); 
registerValidSW:注冊有效serviceWorker
function registerValidSW(swUrl) { //注冊有效的serviceWorker,然后使用提供的API進行操作 navigator.serviceWorker .register(swUrl) .then(registration => { //如果內容有更新,就會自動進行安裝 registration.onupdatefound = () => { const installingWorker = registration.installing; installingWorker.onstatechange = () => { //安裝之后判斷安裝狀態進行提示 if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { console.log('New content is available; please refresh.'); } else { console.log('Content is cached for offline use.'); } } }; }; }) .catch(error => { console.error('Error during service worker registration:', error); }); } 
checkValidServiceWorker:檢測serviceWorker狀態
function checkValidServiceWorker(swUrl) { // 向服務端申請資源 fetch(swUrl) .then(response => { // 如果連接失敗或者沒有返回js if ( response.status === 404 || response.headers.get('content-type').indexOf('javascript') === -1 ) { // 那么當 service worker 狀態就緒的時候取消其注冊狀態 navigator.serviceWorker.ready.then(registration => { registration.unregister().then(() => { //並且重新加載頁面 window.location.reload(); }); }); } else { // 如果申請到資源,那么就調用 registerValidSW 方法來進行加載 registerValidSW(swUrl); } }) .catch(() => { console.log( 'No internet connection found. App is running in offline mode.' ); }); }


 

 

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM