Service Workers 是一項非常棒的技術。您可能知道它們與術語漸進式Web 應用程式(PWA) 相關,因此通常在瀏覽器上可見的內容可以「安裝」在作業系統中,並且可以像本機應用程式一樣打開,並像本機應用程式一樣卸載,看起來就像一個本機應用程式。但服務人員能做的遠不止這些。
有關可訪問性和解釋,請查看此處。
Service Worker 基本上是共享的Web Worker(順便說一句,它作為一種單獨的技術存在),具有攔截瀏覽器從同一 範圍內的URL 發出的所有http 請求 的特殊能力(原始路徑)worker 已註冊。然後,可以指示它使用建構的或快取的回應進行回應 - 實際上阻止瀏覽器透過請求存取網路 - 或正常地將請求傳遞到網路或透過修改請求(使用 fetch)。
這就是說,很明顯為什麼Service Worker 通常與離線時訪問網頁的能力相關聯:第一次可以下載並快取所有靜態資源(基本上是「安裝」)頁面),然後Service Worker 可以使用快取版本回應相同的請求,基本上像本機應用程式一樣提供「應用程式資源」。 dev.to 就是一個很好的例子。
這已經是一個簡化,談論快取清除、更新和其餘內容超出了本文的範圍,所以我不會沉迷於此。我要討論的是 Service Worker 提供建構回應的能力。
我的團隊最近的任務是建立一個「展示」應用程序,即一個基本上不執行任何操作的Web 應用程序,但目的是展示如何按照設計系統使用我們的Web 組件UI 套件以及編碼指南。
該應用程式旨在作為純粹的前端應用程式(意味著我們不應該也開發後端),但應該看起來像我們的客戶維護的眾多B2B 應用程式之一,具有後端和所有功能。這時候 Service Worker 的角色就派上用場了。
現在,透過文字回覆非常簡單。即使 JSON 基本上也是文本,所以最終我們的 Service Worker 可能是這樣的:
self.addEventListener('fetch', event => { if (event.request.url.includes('/api/hello')) { event.respondWith(new Response( JSON.stringify({ message: 'Hello!' }), { headers: { 'Content-Type': 'application/json' }} ); } else { event.respondWith(fetch(event.request)); } });
但是其他類型的動態反應呢?喜歡圖片嗎?
產生動態映像的最簡單方法是建立 SVG,它基本上是一個 XML 文件。意思是,它是文字。這是一項完全可行的任務,您可以使用D3.js 等函式庫為您產生SVG 元素和路徑:像line() 和其他工廠這樣的工廠返回函數,這些函數會傳回您需要放入
self.addEventListener('fetch', event => { if (event.request.url.includes('/api/hello')) { event.respondWith(new Response( JSON.stringify({ message: 'Hello!' }), { headers: { 'Content-Type': 'application/json' }} ); } else { event.respondWith(fetch(event.request)); } });
動態產生 SVG 可以很好地讓任務脫離主執行緒 - 而且結果甚至可以被快取。這對於圖表和資訊圖表來說非常有用,並且足夠“簡單”地完成。
更棘手的是產生光柵影像,如PNG或JPG。 「生成」是指使用編輯工具來改變圖片或從頭開始創建它。在這些情況下我們通常會做的是使用
問題是,Service Worker 無法存取 DOM 元素。那麼,我們運氣不好嗎?
不用擔心,我的朋友們!因為所有worker(包括serviceworker)都可以建立OffscreenCanvas物件。為建構器提供以像素為單位的寬度和高度,然後您就可以在 Service Worker 中看到完美的(儘管不可見)畫布:
import { pie, arc } from 'd3-shape'; const pieData = pie().sort(null)(data); const sectorArc = arc().outerRadius(35).innerRadius(20); const svg = '<svg viewBox="-40 -40 80 80" xmlns="http://www.w3.org/2000/svg">' + pieData.map((pie, index) => `<path d="${sectorArc(pie)}" fill="${colors[index]}"/>` ).join('') + '</svg>'; event.respondWith(new Response( svg, { headers: { 'Content-Type': 'image/svg+xml' }} ));
對於那些想知道的人:是的,您可以獲得不同類型的上下文,儘管並非所有瀏覽器都可用。您可以嘗試使用諸如 Three.js 這樣的函式庫在 Service Worker 中產生 3D 場景(我想我稍後會嘗試)。
現在我們基本上可以做任何事。繪製直線、弧線、路徑等。甚至修改畫布的幾何形狀。這就像在 DOM 畫布上下文上繪圖一樣簡單,所以我不會沉迷於這部分。
我們確實也可以寫文字。這很重要,因為在其他環境中 - 即 Paint 工作集,我們不能這樣做:
注意:PaintRenderingContext2D 實作了 CanvasRenderingContext2D API 的子集。具體來說,它沒有實作 CanvasImageData、CanvasUserInterface、CanvasText 或 CanvasTextDrawingStyles API。
但對於 Service Worker 來說,這一切都很好。這意味著我們有一個更強大(儘管性能較差)的環境來產生背景圖像。
繪製文字就這麼簡單:
const canvas = new OffscreenCanvas(800, 600); const context = canvas.getContext('2d');
你可以使用你喜歡的字體,但我發現通常的標準值,如sans-serif、等寬字體或system-ui 似乎不起作用,因為它們都會回退到預設襯線字體。但您可以照常使用字體堆疊:
context.fillStyle = '#222'; context.font = '24px serif'; // (x, y) = (50, 90) will be the *bottom left* corner of the text context.fillText('Hello, world!', 50, 90);
此外,您可以使用字型載入API從外部資源載入字型:
self.addEventListener('fetch', event => { if (event.request.url.includes('/api/hello')) { event.respondWith(new Response( JSON.stringify({ message: 'Hello!' }), { headers: { 'Content-Type': 'application/json' }} ); } else { event.respondWith(fetch(event.request)); } });
發迴回應就像呼叫 ConvertToBlob 方法一樣簡單,該方法傳回一個 Blob(你猜對了)的承諾。並且 Blob 可以輕鬆發送回寄件者。
import { pie, arc } from 'd3-shape'; const pieData = pie().sort(null)(data); const sectorArc = arc().outerRadius(35).innerRadius(20); const svg = '<svg viewBox="-40 -40 80 80" xmlns="http://www.w3.org/2000/svg">' + pieData.map((pie, index) => `<path d="${sectorArc(pie)}" fill="${colors[index]}"/>` ).join('') + '</svg>'; event.respondWith(new Response( svg, { headers: { 'Content-Type': 'image/svg+xml' }} ));
此方法預設會建立一個 PNG 映像,但可以指示建立一個 JPG 文件,如上所示。 「image/webp」是另一種常見格式,但 Safari 不支援它。老實說,這裡的選擇有點令人印象深刻,因為新可用且功能更強大的圖像格式解碼器並未反映在其相應的編碼器中。但這對於大多數用途來說已經足夠了。
有趣的事實:convertToBlob 方法特定於 OffscreenCanvas 類別。 HTMLCanvasElements 具有 toBlob,它採用回呼作為第一個參數,採用常見的前 Promise 時代非同步任務處理風格。
現在,如果我們想要從頭開始建立圖片,這一切都有效。但是如果我們想從空白模板開始呢?
如果我們要在主執行緒中工作,我們可以使用 2D 上下文的 drawImage 方法在上下文中繪製圖片,例如取得它來自現成的 元素。
問題再次出現,我們無法存取 DOM,因此無法引用 元素。相反,我們可以做的是,它獲取我們需要作為背景的圖片,獲取其Blob,然後將其轉換為drawImage可以消化的其他內容。輸入 createImageBitmap,這是一個在 Service Worker 中也可用的全域方法。它傳回一個 ImageBitmap 實例的承諾,這是前端 Web 開發中許多鮮為人知的類別之一。它顯然在 WebGL 上下文中使用更廣泛,但 drawImage 似乎接受它,所以...
const canvas = new OffscreenCanvas(800, 600); const context = canvas.getContext('2d');
從現在開始,我們可以繼續在其上繪製塗鴉和文本,創建令人滿意的同步圖像並將其發回給用戶。
注意:使用 SVG 可以更輕鬆地解決這個問題,因為您可以只使用
元素來設定背景圖片。但這意味著瀏覽器必須在發送生成的圖像之後加載圖片,而使用這種技術,這是在之前完成的。選擇字體時也有類似的情況。
在所有這些範例中,我使用了模組服務工作者(即我使用了從其他ES模組匯入)。遺憾的是,Firefox 尚不支援模組服務工作者,但希望很快就會支援。同時,您可能需要調整程式碼以使用舊的 importScripts。
透過import 或importScripts 將其他腳本匯入服務工作人員時,請記住,當匯入的檔案發生變更時,瀏覽器將不會觸發updatefound 事件:它僅在下列情況下觸發Service Worker 入口腳本發生變更。
在像我們這樣的情況下,服務工作者只需要模擬後端的存在,它的生命週期可以透過在安裝事件觸發時立即呼叫self.skipWaiting() 來縮短,然後呼叫self.在啟動事件上呼叫clients.claim(),以便能夠立即回應請求(否則,它只會在下一頁刷新時啟動)。
self.addEventListener('fetch', event => { if (event.request.url.includes('/api/hello')) { event.respondWith(new Response( JSON.stringify({ message: 'Hello!' }), { headers: { 'Content-Type': 'application/json' }} ); } else { event.respondWith(fetch(event.request)); } });
這基本上就是一切,所以...和服務人員一起玩吧,夥計們!
以上是使用 Service Worker 建立動態影像的詳細內容。更多資訊請關注PHP中文網其他相關文章!