怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題-創(chuàng)新互聯(lián)

這篇文章主要介紹怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)公司長(zhǎng)期為上千客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為永和企業(yè)提供專業(yè)的網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,永和網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

傳統(tǒng)方案的困境

無(wú)論是 html 離線,還是直出,以及讓 webview 啟動(dòng)和網(wǎng)絡(luò)請(qǐng)求并行 ,頁(yè)面的切換和打開(kāi)都無(wú)法避免 html 加載這一過(guò)程。對(duì)于大型應(yīng)用而言,龐大的 js 初始化解析和執(zhí)行會(huì)耗費(fèi)巨大的時(shí)間。

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

新的思考方向?

速度優(yōu)化的本質(zhì)是以空間換時(shí)間。我們是否可以從這個(gè)思路,將打開(kāi) webview 及解析 html 這以過(guò)程省略掉呢?答案是可以的。

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

容器化方案

容器化 即是我們最終探索與實(shí)踐的出來(lái)的一套方案。正常 web 頁(yè)面關(guān)閉后,webview 組件即會(huì)銷毀掉,下一次再打開(kāi)需要重新啟動(dòng)。通常讓 webview 保持常駐的做法可以節(jié)省 webview 啟動(dòng)時(shí)間, 但簡(jiǎn)單的常駐 webview 并不能做到頁(yè)面秒開(kāi),頁(yè)面打開(kāi)仍然需要重新解析 html。

對(duì)于我們的應(yīng)用特征而言,頁(yè)面切換實(shí)際上是僅僅內(nèi)容數(shù)據(jù)的變化,比如切換一篇文檔,其 html 容器及樣式都是同一套,而差異僅僅只是在數(shù)據(jù)上,重新載入 html 及初始化 js 這部分耗時(shí)完全可以避免掉。讓 webview 組件及其容器內(nèi)的 html 頁(yè)面常駐,在文檔切換的過(guò)程,僅僅對(duì)數(shù)據(jù)進(jìn)行替換,這即是容器化方案。容器化方案省去了 webview 重復(fù)啟動(dòng)和渲染 html 的問(wèn)題,打開(kāi)文檔,耗時(shí)只在做數(shù)據(jù)替換,真正做到了秒開(kāi)。

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

容器切換

web 側(cè)如何感知到不同的頁(yè)面在進(jìn)行互切換,數(shù)據(jù)如何做到替換呢?

首先在 app 打開(kāi)的時(shí)候,文檔列表會(huì)進(jìn)行數(shù)據(jù)預(yù)拉取,同時(shí)觸發(fā)客戶端預(yù)啟動(dòng)容器,除此外,其他任意場(chǎng)景也能按需觸發(fā)容器啟動(dòng)(后面會(huì)聊到)。容器內(nèi)會(huì)提前進(jìn)行 html 渲染和 js 執(zhí)行,此時(shí)的數(shù)據(jù)是空的。用戶點(diǎn)擊文檔,客戶端會(huì)對(duì)打開(kāi) url 這一行為進(jìn)行監(jiān)聽(tīng),同時(shí)解析 url,取出標(biāo)識(shí)符, 判斷本地是否已經(jīng)存在并且符合要求的數(shù)據(jù),如果條件命中,直接使用已經(jīng)打開(kāi)的容器切出,通知到容器內(nèi)的 web,web 收到通知,通過(guò) url 取出標(biāo)識(shí)符,從本地進(jìn)行數(shù)據(jù)獲取,然后對(duì)數(shù)據(jù)進(jìn)行替換渲染,從而完成頁(yè)面切換。

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

容器化數(shù)據(jù)替換

直接容器替換的思路省去了代碼加載和解析時(shí)間,但對(duì)于前端代碼而言,需要支持直接替換數(shù)據(jù)。大部分前端項(xiàng)目代碼設(shè)計(jì)都是自執(zhí)行調(diào)用 方式,支持容器化的前提是:需要對(duì)代碼改造成可支持數(shù)據(jù)組裝和銷毀

// 大部分應(yīng)用加載頁(yè)面初始化的場(chǎng)景
class App {
    public init() {
     initA();
     initB();
        // 初始化各種模塊
        ...
    }
}
 
const app = new App();
app.init();

自執(zhí)行調(diào)用后,大量的內(nèi)部依賴模塊也依次進(jìn)行初始化,然后數(shù)據(jù)常駐在內(nèi)存中,通常對(duì)于加載一個(gè)正常網(wǎng)頁(yè)而言,用戶每次都是新開(kāi)頁(yè)面,加載 html, 重新進(jìn)行解析和初始化,并不會(huì)帶來(lái)什么問(wèn)題。但是按照容器化思路,頁(yè)面不會(huì)重新載入,只進(jìn)行數(shù)據(jù)替代,對(duì)于大型應(yīng)用而言意味著成千上萬(wàn)的模塊需要支持內(nèi)存釋放和數(shù)據(jù)切換,一旦沒(méi)有處理好,會(huì)面臨嚴(yán)重的內(nèi)存泄露和代碼健壯性問(wèn)題。如何組織和管理這些代碼,支持可插拔式,讓整個(gè)頁(yè)面初始化流程都能鏈?zhǔn)浇M裝,可以進(jìn)行配置,是進(jìn)行容器化代碼改造的難點(diǎn)。

  • 依賴倒置

依賴倒置原則的是指內(nèi)部模塊不應(yīng)該依賴外部模塊,底層模塊不應(yīng)該依賴上層模塊。

哪些才是底層模塊,哪些才是上層模塊呢?通常而言,越穩(wěn)定不變邏輯,應(yīng)該是越底層,越接近用戶交互,容易變化的部分是上層。具體層級(jí)劃分需要分析應(yīng)用的結(jié)構(gòu)和依賴關(guān)系,良好劃分層級(jí)的應(yīng)用是容器化改造的前提。

  • 職責(zé)鏈模式

職責(zé)鏈模式是指每個(gè)對(duì)象都有接受請(qǐng)求的可能,這些對(duì)象連接成一條鏈,請(qǐng)求沿著這條鏈的傳遞,直到有對(duì)象處理,這樣做的好處是減少接受者和發(fā)送者直接的耦合。比如在一個(gè)頁(yè)面加載生命周期中,我們可以讓內(nèi)部模塊到外部模塊都實(shí)現(xiàn)相應(yīng)的生命周期職責(zé),應(yīng)用啟動(dòng)和銷毀的過(guò)程,請(qǐng)求沿著指定鏈條從外到內(nèi)傳遞,也可以按需指定跳躍某個(gè)模塊,這樣大大降低了模塊之間的耦合,從而更好的管理代碼。

export default interface IRestart{
    emitter: EventEmitter;
    startDestroy(): void;
    destroy(): void;
    restart(): void;
    restartEnd(): void;
    // ...
}
class Page {
    next: PageFlow|null;
    cache: {
        start: (() => Promise<any>)[];
        end: (() => Promise<any>)[];
    };
    waitStart(callback: () => Promise<any>) {
        this.cache.start.push(callback);
    };
    waitEnd(callback: () => Promise<any>) {
        this.cache.end.push(callback);
    };
    setNext(flow: PageFlow) {
        this.next = flow;
        return flow;
    }
     // ...
   }
  • 依賴注入

所謂依賴注入是當(dāng)指 A 對(duì)象依賴另一個(gè) B 對(duì)象時(shí),不直接在 A 對(duì)象內(nèi)初始化 B,而是通過(guò)外部環(huán)境進(jìn)行初始化,作為參數(shù)傳入 A 對(duì)象中。這樣做的好處是當(dāng) B 模塊的初始化等條件發(fā)生變化時(shí),不必在 A 對(duì)象中進(jìn)行重復(fù)的修改。管理成百上千個(gè)這樣模塊相互依賴的代碼中,統(tǒng)一的依賴注入管理器會(huì)讓依賴關(guān)系管理變得更方便。

// 模塊加載器
class ServiceLoader {
    source: CONFIG;
    loaded: boolean;    // 是否已加載
    initialized: boolean;   // 是否已初始
    module: any;
    constructor(source: CONFIG) {
        this.loaded = false;
        this.initialized = false;
        // ...
    }
    async load(params?: any): Promise<any> {
     // ..load module
        return this.module;
    }
    //...
}
// 模塊管理器
class ServiceCollection {
    stack: ServiceLoader[];
    private services = new Map<CONFIG, ServiceLoader>();
    constructor() {
        this.stack = [];
    }
    createLoader(config: CONFIG): ServiceLoader {
        const loader: ServiceLoader =  new ServiceLoader(config);
        this.services.set(config, loader);
        return loader;
    }
    // ...
}
initA () {
    const ALoader= this.serviceCollection.createLoader(CONFIG.A);
    const discussMobile = ALoader.init(this.app);
}

數(shù)據(jù)預(yù)拉服務(wù)

容器是否會(huì)命中依賴兩個(gè)條件,其一對(duì)應(yīng)離線包代碼是否下載好;其二對(duì)應(yīng)版本的數(shù)據(jù)是否已經(jīng)預(yù)拉緩存完畢。

用戶進(jìn)入文檔管理首頁(yè),首先會(huì)去拉取列表索引數(shù)據(jù),然后通過(guò)列表數(shù)據(jù) id 進(jìn)行文檔內(nèi)容數(shù)據(jù)做預(yù)拉,儲(chǔ)存在本地?cái)?shù)據(jù)庫(kù),本地?cái)?shù)據(jù)庫(kù)的存儲(chǔ)可以參考前端離線化探索。

webview service

在整個(gè)數(shù)據(jù)預(yù)拉的過(guò)程,我們是通過(guò)一套獨(dú)立的客戶端后臺(tái) webview 服務(wù)執(zhí)行具體任務(wù),獨(dú)立服務(wù)的好處是讓各種容器化基礎(chǔ)服務(wù)和文檔管理列表本身進(jìn)行解耦,同時(shí)將拉取、解析、儲(chǔ)存數(shù)據(jù)這一對(duì)性能有消耗的過(guò)程放后臺(tái)服務(wù),減少了列表用戶交互界面層的性能壓力。

另一方面,作為多端公用的一個(gè)服務(wù),構(gòu)建流程上單獨(dú)部署,更新代碼的時(shí)候能夠不依賴其他頁(yè)面,變得更靈活。

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

數(shù)據(jù)快照

對(duì)于純 dom 結(jié)構(gòu)的文檔型品類,我們會(huì)在打開(kāi)文檔,解析數(shù)據(jù)后,把生成的 html 緩存在本地?cái)?shù)據(jù)庫(kù)一張快照表里。下一次切換容器時(shí),在取本地?cái)?shù)據(jù)去解析的同時(shí),會(huì)判斷對(duì)應(yīng) id 在快照表是否存在緩存,如果有,直接取出來(lái),覆蓋在 html 上,用戶可以提前看到上一次渲染的數(shù)據(jù),等本地?cái)?shù)據(jù)真正解析完,再展示可交互界面。解析數(shù)據(jù)準(zhǔn)備渲染也是需要一個(gè)上百毫秒的過(guò)程,這一策略可以讓用戶提前看到內(nèi)容。

預(yù)創(chuàng)建

有了極致的打開(kāi)速度,如何優(yōu)化新建速度呢。正常的新建流程是這樣的,用戶點(diǎn)擊新建按鈕,前端請(qǐng)求創(chuàng)建 cgi, 等待后臺(tái)創(chuàng)建成功返回新文檔 url,前端再新開(kāi) webview,加載展示頁(yè)面。我們可以看,由于需要等待創(chuàng)建接口返回的原因,到新建的過(guò)程比正常打開(kāi)一個(gè)文檔還要更久。

怎么樣才能讓新建也做到秒開(kāi)呢?思路和數(shù)據(jù)預(yù)拉取一樣,在用戶進(jìn)入文檔首頁(yè)的同時(shí),我們會(huì)提前預(yù)請(qǐng)求一批創(chuàng)建 id,然后緩存到本地,同時(shí)根據(jù)創(chuàng)建 id 生成一篇空白文檔數(shù)據(jù),儲(chǔ)存在本地,標(biāo)示狀態(tài)為未使用。用戶點(diǎn)擊新建按鈕,本質(zhì)上是從本地取一個(gè)未使用的文檔 url,直接用容器切換打開(kāi),然后再和后臺(tái)進(jìn)行同步。

秒開(kāi)效果

容器化方案前:

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

容器化方案后:

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

監(jiān)控與開(kāi)關(guān)系統(tǒng)

容器方案使用了數(shù)據(jù)預(yù)取場(chǎng)景,命中率的監(jiān)控非常重要。由于切換頁(yè)面的過(guò)程,如果命中容器,我們會(huì)接受來(lái)自客戶端的通知,在這個(gè)時(shí)機(jī),我們可以進(jìn)行上報(bào)。

另外一個(gè)非常重要的是容器能力的開(kāi)關(guān)系統(tǒng),在發(fā)布之初保持現(xiàn)網(wǎng)穩(wěn)定性是非常重要的措施,但任何程序都不能保證沒(méi)有 bug,我們通過(guò)內(nèi)部七彩石配置系統(tǒng)控制這套容器方案的各種特性在不同品類下是否啟用,同時(shí)這套配置也支持灰度和回滾方案,能夠應(yīng)急各種突發(fā)問(wèn)題。

灰度期容器間命中率

怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題

待優(yōu)化的問(wèn)題

容器化方案用各種預(yù)創(chuàng)建 webview 的方式換取了打開(kāi)速度,app 內(nèi)存占用上會(huì)比未使用容器化方案要大非常多,webview 的釋放時(shí)機(jī)、預(yù)加載數(shù)據(jù)的策略優(yōu)化,及從客戶端到 web 端,如何更好的做內(nèi)存管理是接下來(lái)需要進(jìn)一步優(yōu)化的點(diǎn)。

以上是“怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

網(wǎng)頁(yè)名稱:怎么解決HTML5頁(yè)面無(wú)縫閃開(kāi)的問(wèn)題-創(chuàng)新互聯(lián)
鏈接地址:http://muchs.cn/article34/ceccpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)小程序開(kāi)發(fā)、網(wǎng)站內(nèi)鏈外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站排名、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)