摘要:本文將介紹來自顧問團隊的國際同事原創(chuàng)的緩存范例,利用廣泛用于開發(fā)的典型接口實現。因而在緩存模型時,可以調用該接口緩存所有相關的,無需用到。代碼示例我們制作了讓用戶選擇模型作離線緩存的例子,查看代碼請訪問,在線演示請訪問。
演示視頻:http://www.bilibili.com/video...
由于Autodesk Forge是完全基于RESTful API框架的云平臺,且暫時沒有本地部署方案,特別是Viewer.js暫不支持本地搭建,必須外部引用位于服務器端的腳本,如何滿足離線應用的需求一直是廣大開發(fā)者關注的問題。本文將介紹來自Forge顧問團隊的國際同事Petr原創(chuàng)的Viewer緩存范例,利用HTML5廣泛用于PWA(Progressive Web App)開發(fā)的典型接口實現。
時至今日,要把來自網絡應用或服務的數據緩存至本地設備,我們有幾種不同的技術與方式可選,本文將示范使用Service Worker,Cache和Channel Messaging等API實現,它們都是開發(fā)Progrssive Web App的常客。雖然這些API相對較為新銳,但已獲得新版瀏覽器的廣發(fā)支持,詳細支持情況可以參考(詳見“瀏覽器兼容性”部分):
Service Worker: https://developer.mozilla.org...
Channel Messaing:https://developer.mozilla.org...
Cache: https://developer.mozilla.org...
Worker: https://developer.mozilla.org...
當我們在JavaScript中注冊了Service Worker之后,該Worker會攔截瀏覽器所有頁面對于指定網絡源或域的請求,返回緩存中的內容,Service Worker亦可以調用IndexDB、Channel Messaging、Push等API。Service Worker在特殊的Worker上下文(ServiceWorkerGlobalScope)中執(zhí)行,無法直接對DOM進行操作,可以獨立于頁面的形式控制頁面的加載。一個Service Worker可以控制多個頁面,每當指定范圍內的頁面加載時,Service Worker便于會對其進行安裝并操作,所以請小心使用全局變量,每個頁面并沒有自身獨立的Worker。
作為一種特殊的Web Worker,Service Worker的生命周期如下:
在JavaScript中注冊Service Worker
瀏覽器下載并執(zhí)行Worker腳本
Worker收到“install”(安裝)事件,一次性配置所需資源
等待其他正在執(zhí)行的Service Worker結束(頁面關閉)
Worker收到“activate”(激活)事件,清除Worker的舊cache,并按需接管Worker
Worker開始接受“fetch”(攔截網絡請求并返回緩存中的資源)和“message”(與前端代碼通訊)事件:
Cache是一個存儲API,與LocalStorage及IndexDB類似,每個網絡源或域都有自己對應的存儲空間,其中包括不重名的cache對象,用于存儲HTTP請求與應答內容。
Channel Messaging是腳本之間通訊API,支持包括主頁面、iframe、Web Worker、Service Worker之間的雙向通訊。
緩存策略緩存諸如靜態(tài)資源和API端口返回的數據并不復雜,可在Service Worker安裝時緩存即可。然后,當頁面向API端口發(fā)送請求時,Service Worker會當即返回緩存的內容,且可按需在后臺拉取資源并更新緩存內容。
緩存模型就稍許繁瑣,一個模型通常會轉換生成數個資源,生成的資源也時常引用其他素材,所以需要找出所有這些依賴并按需將其緩存。在本文的代碼示例中,我們在后臺寫有接口,可根據模型的URN查詢并返回所需資源的URL列表。因而在緩存模型時,Service Worker可以調用該接口緩存所有相關的URL,無需用到Viewer。
代碼示例我們制作了讓用戶選擇模型作離線緩存的例子,查看代碼請訪問:https://github.com/petrbroz/f...,在線演示請訪問:https://forge-offline.herokua...。接下來我們講解一些具體的代碼片段。
例子的后臺基于Express,public目錄的內容作靜態(tài)托管,其它服務端口位于以下三個路徑:
GET /api/token - 返回驗證Token
GET /api/models - 返回可瀏覽的模型列表
GET /api/models/:urn/files - 根據模型的URN查詢并返回所需資源的URL列表
客戶端包括兩個核心腳本:public/javascript/main.js和public/service-worker.js,其中public/javascript/main.js主要用于配置Viewer和UI邏輯,有兩個重要的函數在腳本底部:initServiceWorker和submitWorkerTask,前者觸發(fā)Service Worker的注冊,后者向其發(fā)送消息:
async function initServiceWorker() { try { const registration = await navigator.serviceWorker.register("/service-worker.js"); console.log("Service worker registered", registration.scope); } catch (err) { console.error("Could not register service worker", err); } }
在“activate”事件中,本例并無清理舊Worker的需要,于是直接接管并控制所有Service Worker:
async function activateAsync() { const clients = await self.clients.matchAll({ includeUncontrolled: true }); console.log("Claiming clients", clients.map(client => client.url).join(",")); await self.clients.claim(); }
攔截請求時,我們優(yōu)選比對并返回緩存中的內容,除了GET /api/token將優(yōu)先嘗試獲取新的Token,因為Token是有時效性的,只有獲取新Token失敗時我們才使用緩存:
async function fetchAsync(event) { // 優(yōu)先獲取新Token而非使用緩存 if (event.request.url.endsWith("/api/token")) { try { const response = await fetch(event.request); return response; } catch(err) { console.log("Could not fetch new token, falling back to cache.", err); } } // 如緩存匹配成功,直接返回其內容 const match = await caches.match(event.request.url, { ignoreSearch: true }); if (match) { // 如請求指向靜態(tài)資源或我們制定范圍內的API,同時后臺更新緩存 if (STATIC_URLS.includes(event.request.url) || API_URLS.includes(event.request.url)) { caches.open(CACHE_NAME) .then((cache) => cache.add(event.request)) .catch((err) => console.log("Cache not updated, but that"s ok...", err)); } return match; } return fetch(event.request); }
最后,使用Channel Messaging API執(zhí)行從頁面腳本發(fā)起的任務:
async function messageAsync(event) { switch (event.data.operation) { case "CACHE_URN": try { const urls = await cacheUrn(event.data.urn, event.data.access_token); event.ports[0].postMessage({ status: "ok", urls }); } catch(err) { event.ports[0].postMessage({ error: err.toString() }); } break; case "CLEAR_URN": try { const urls = await clearUrn(event.data.urn); event.ports[0].postMessage({ status: "ok", urls }); } catch(err) { event.ports[0].postMessage({ error: err.toString() }); } break; case "LIST_CACHES": try { const urls = await listCached(); event.ports[0].postMessage({ status: "ok", urls }); } catch(err) { event.ports[0].postMessage({ error: err.toString() }); } break; } } async function cacheUrn(urn, access_token) { console.log("Caching", urn); // 首先從后臺獲取URN所需資源的URL列表 const baseUrl = "https://developer.api.autodesk.com/derivativeservice/v2"; const res = await fetch(`/api/models/${urn}/files`); const derivatives = await res.json(); // 初始化拉取請求以便緩存資源 const cache = await caches.open(CACHE_NAME); const options = { headers: { "Authorization": "Bearer " + access_token } }; const fetches = []; const manifestUrl = `${baseUrl}/manifest/${urn}`; fetches.push(fetch(manifestUrl, options).then(resp => cache.put(manifestUrl, resp)).then(() => manifestUrl)); for (const derivative of derivatives) { const derivUrl = baseUrl + "/derivatives/" + encodeURIComponent(derivative.urn); fetches.push(fetch(derivUrl, options).then(resp => cache.put(derivUrl, resp)).then(() => derivUrl)); for (const file of derivative.files) { const fileUrl = baseUrl + "/derivatives/" + encodeURIComponent(derivative.basePath + file); fetches.push(fetch(fileUrl, options).then(resp => cache.put(fileUrl, resp)).then(() => fileUrl)); } } // 并發(fā)執(zhí)行拉取請求并緩存資源 const urls = await Promise.all(fetches); return urls; } async function clearUrn(urn) { console.log("Clearing cache", urn); const cache = await caches.open(CACHE_NAME); const requests = (await cache.keys()).filter(req => req.url.includes(urn)); await Promise.all(requests.map(req => cache.delete(req))); return requests.map(req => req.url); } async function listCached() { console.log("Listing caches"); const cache = await caches.open(CACHE_NAME); const requests = await cache.keys(); return requests.map(req => req.url); }
以上。在線演示請訪問: https://forge-offline.herokua...,點擊左上角模型旁邊的“☆”觸發(fā)緩存, 請參考本文開頭所示使用支持所需API的瀏覽器訪問。
延伸閱讀:
一文讀懂Service Worker
Web Worker、Service Worker與Shared Worker分不清楚?
Service Worker、Web Worker和Websocket
PWA速成
Cache和Application Cache
關于消息通道(Channel Messaging)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101177.html
摘要:默認情況下,是英文環(huán)境,調取的是的資源其實無需翻譯。但是,如前面提到的,語言包只是包含了部分常規(guī)字串的翻譯,如果遇到沒有包含的常規(guī)字串怎么辦呢例如,本例中的語言包并沒有對,進行翻譯,所以即使切換了語言,它們仍舊是英文。 注:本文是個人調試分析所得,非官方文檔,請酌情選用參考。文中分析的數據由https://extract.autodesk.io轉換下載而來。 談到信息本地化,個人覺得包...
摘要:經過一系列優(yōu)化后,在平臺上,點擊到頁面首屏展示的耗時從平均多降低為,優(yōu)化以上。而現在頁面為了更好地為用戶推薦喜歡的內容,我們后臺引入機器學習和隨機算法來做智能個性化推薦。另外還有部分的內容是隨機算法推薦的。 VasSonic成長歷程 前言 2017.8.8 14時,SNG增值產品部Vas團隊研發(fā)的輕量級高性能Hybrid框架VasSonic通過了公司最終審核,作為騰訊開源組件分享給大...
閱讀 3537·2021-09-10 10:51
閱讀 2507·2021-09-07 10:26
閱讀 2482·2021-09-03 10:41
閱讀 810·2019-08-30 15:56
閱讀 2896·2019-08-30 14:16
閱讀 3488·2019-08-30 13:53
閱讀 2103·2019-08-26 13:48
閱讀 1913·2019-08-26 13:37