亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Viewer模型加載本地離線緩存實(shí)戰(zhàn)

oogh / 1690人閱讀

摘要:本文將介紹來(lái)自顧問(wèn)團(tuán)隊(duì)的國(guó)際同事原創(chuàng)的緩存范例,利用廣泛用于開(kāi)發(fā)的典型接口實(shí)現(xiàn)。因而在緩存模型時(shí),可以調(diào)用該接口緩存所有相關(guān)的,無(wú)需用到。代碼示例我們制作了讓用戶選擇模型作離線緩存的例子,查看代碼請(qǐng)?jiān)L問(wèn),在線演示請(qǐng)?jiān)L問(wèn)。

演示視頻:http://www.bilibili.com/video...

由于Autodesk Forge是完全基于RESTful API框架的云平臺(tái),且暫時(shí)沒(méi)有本地部署方案,特別是Viewer.js暫不支持本地搭建,必須外部引用位于服務(wù)器端的腳本,如何滿足離線應(yīng)用的需求一直是廣大開(kāi)發(fā)者關(guān)注的問(wèn)題。本文將介紹來(lái)自Forge顧問(wèn)團(tuán)隊(duì)的國(guó)際同事Petr原創(chuàng)的Viewer緩存范例,利用HTML5廣泛用于PWA(Progressive Web App)開(kāi)發(fā)的典型接口實(shí)現(xiàn)。

時(shí)至今日,要把來(lái)自網(wǎng)絡(luò)應(yīng)用或服務(wù)的數(shù)據(jù)緩存至本地設(shè)備,我們有幾種不同的技術(shù)與方式可選,本文將示范使用Service Worker,Cache和Channel Messaging等API實(shí)現(xiàn),它們都是開(kāi)發(fā)Progrssive Web App的??汀km然這些API相對(duì)較為新銳,但已獲得新版瀏覽器的廣發(fā)支持,詳細(xì)支持情況可以參考(詳見(jiàn)“瀏覽器兼容性”部分):

Service Worker: https://developer.mozilla.org...

Channel Messaing:https://developer.mozilla.org...

Cache: https://developer.mozilla.org...

Worker: https://developer.mozilla.org...

當(dāng)我們?cè)贘avaScript中注冊(cè)了Service Worker之后,該Worker會(huì)攔截瀏覽器所有頁(yè)面對(duì)于指定網(wǎng)絡(luò)源或域的請(qǐng)求,返回緩存中的內(nèi)容,Service Worker亦可以調(diào)用IndexDB、Channel Messaging、Push等API。Service Worker在特殊的Worker上下文(ServiceWorkerGlobalScope)中執(zhí)行,無(wú)法直接對(duì)DOM進(jìn)行操作,可以獨(dú)立于頁(yè)面的形式控制頁(yè)面的加載。一個(gè)Service Worker可以控制多個(gè)頁(yè)面,每當(dāng)指定范圍內(nèi)的頁(yè)面加載時(shí),Service Worker便于會(huì)對(duì)其進(jìn)行安裝并操作,所以請(qǐng)小心使用全局變量,每個(gè)頁(yè)面并沒(méi)有自身獨(dú)立的Worker。

作為一種特殊的Web Worker,Service Worker的生命周期如下:

在JavaScript中注冊(cè)Service Worker

瀏覽器下載并執(zhí)行Worker腳本

Worker收到“install”(安裝)事件,一次性配置所需資源

等待其他正在執(zhí)行的Service Worker結(jié)束(頁(yè)面關(guān)閉)

Worker收到“activate”(激活)事件,清除Worker的舊cache,并按需接管Worker

Worker開(kāi)始接受“fetch”(攔截網(wǎng)絡(luò)請(qǐng)求并返回緩存中的資源)和“message”(與前端代碼通訊)事件:

Cache是一個(gè)存儲(chǔ)API,與LocalStorage及IndexDB類似,每個(gè)網(wǎng)絡(luò)源或域都有自己對(duì)應(yīng)的存儲(chǔ)空間,其中包括不重名的cache對(duì)象,用于存儲(chǔ)HTTP請(qǐng)求與應(yīng)答內(nèi)容。

Channel Messaging是腳本之間通訊API,支持包括主頁(yè)面、iframe、Web Worker、Service Worker之間的雙向通訊。

緩存策略

緩存諸如靜態(tài)資源和API端口返回的數(shù)據(jù)并不復(fù)雜,可在Service Worker安裝時(shí)緩存即可。然后,當(dāng)頁(yè)面向API端口發(fā)送請(qǐng)求時(shí),Service Worker會(huì)當(dāng)即返回緩存的內(nèi)容,且可按需在后臺(tái)拉取資源并更新緩存內(nèi)容。

緩存模型就稍許繁瑣,一個(gè)模型通常會(huì)轉(zhuǎn)換生成數(shù)個(gè)資源,生成的資源也時(shí)常引用其他素材,所以需要找出所有這些依賴并按需將其緩存。在本文的代碼示例中,我們?cè)诤笈_(tái)寫(xiě)有接口,可根據(jù)模型的URN查詢并返回所需資源的URL列表。因而在緩存模型時(shí),Service Worker可以調(diào)用該接口緩存所有相關(guān)的URL,無(wú)需用到Viewer。

代碼示例

我們制作了讓用戶選擇模型作離線緩存的例子,查看代碼請(qǐng)?jiān)L問(wèn):https://github.com/petrbroz/f...,在線演示請(qǐng)?jiān)L問(wèn):https://forge-offline.herokua...。接下來(lái)我們講解一些具體的代碼片段。

例子的后臺(tái)基于Express,public目錄的內(nèi)容作靜態(tài)托管,其它服務(wù)端口位于以下三個(gè)路徑:

GET /api/token - 返回驗(yàn)證Token

GET /api/models - 返回可瀏覽的模型列表

GET /api/models/:urn/files - 根據(jù)模型的URN查詢并返回所需資源的URL列表

客戶端包括兩個(gè)核心腳本:public/javascript/main.jspublic/service-worker.js,其中public/javascript/main.js主要用于配置Viewer和UI邏輯,有兩個(gè)重要的函數(shù)在腳本底部:initServiceWorkersubmitWorkerTask,前者觸發(fā)Service Worker的注冊(cè),后者向其發(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”事件中,本例并無(wú)清理舊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();
}

攔截請(qǐng)求時(shí),我們優(yōu)選比對(duì)并返回緩存中的內(nèi)容,除了GET /api/token將優(yōu)先嘗試獲取新的Token,因?yàn)門(mén)oken是有時(shí)效性的,只有獲取新Token失敗時(shí)我們才使用緩存:

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);
        }
    }

    // 如緩存匹配成功,直接返回其內(nèi)容
    const match = await caches.match(event.request.url, { ignoreSearch: true });
    if (match) {
        // 如請(qǐng)求指向靜態(tài)資源或我們制定范圍內(nèi)的API,同時(shí)后臺(tái)更新緩存
        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í)行從頁(yè)面腳本發(fā)起的任務(wù):

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);
    // 首先從后臺(tái)獲取URN所需資源的URL列表
    const baseUrl = "https://developer.api.autodesk.com/derivativeservice/v2";
    const res = await fetch(`/api/models/${urn}/files`);
    const derivatives = await res.json();
    // 初始化拉取請(qǐng)求以便緩存資源
    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í)行拉取請(qǐng)求并緩存資源
    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);
}

以上。在線演示請(qǐng)?jiān)L問(wèn): https://forge-offline.herokua...,點(diǎn)擊左上角模型旁邊的“☆”觸發(fā)緩存, 請(qǐng)參考本文開(kāi)頭所示使用支持所需API的瀏覽器訪問(wèn)。

延伸閱讀:

一文讀懂Service Worker

Web Worker、Service Worker與Shared Worker分不清楚?

Service Worker、Web Worker和Websocket

PWA速成

Cache和Application Cache

關(guān)于消息通道(Channel Messaging)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/101177.html

相關(guān)文章

  • Autodesk Forge Viewer 信息本地化技術(shù)分析

    摘要:默認(rèn)情況下,是英文環(huán)境,調(diào)取的是的資源其實(shí)無(wú)需翻譯。但是,如前面提到的,語(yǔ)言包只是包含了部分常規(guī)字串的翻譯,如果遇到?jīng)]有包含的常規(guī)字串怎么辦呢例如,本例中的語(yǔ)言包并沒(méi)有對(duì),進(jìn)行翻譯,所以即使切換了語(yǔ)言,它們?nèi)耘f是英文。 注:本文是個(gè)人調(diào)試分析所得,非官方文檔,請(qǐng)酌情選用參考。文中分析的數(shù)據(jù)由https://extract.autodesk.io轉(zhuǎn)換下載而來(lái)。 談到信息本地化,個(gè)人覺(jué)得包...

    littleGrow 評(píng)論0 收藏0
  • 騰訊祭出大招VasSonic,讓你的H5頁(yè)面首屏秒開(kāi)

    摘要:經(jīng)過(guò)一系列優(yōu)化后,在平臺(tái)上,點(diǎn)擊到頁(yè)面首屏展示的耗時(shí)從平均多降低為,優(yōu)化以上。而現(xiàn)在頁(yè)面為了更好地為用戶推薦喜歡的內(nèi)容,我們后臺(tái)引入機(jī)器學(xué)習(xí)和隨機(jī)算法來(lái)做智能個(gè)性化推薦。另外還有部分的內(nèi)容是隨機(jī)算法推薦的。 VasSonic成長(zhǎng)歷程 前言 2017.8.8 14時(shí),SNG增值產(chǎn)品部Vas團(tuán)隊(duì)研發(fā)的輕量級(jí)高性能Hybrid框架VasSonic通過(guò)了公司最終審核,作為騰訊開(kāi)源組件分享給大...

    xzavier 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<