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

這篇文章主要介紹怎么解決HTML5頁(yè)面無(wú)縫閃開的問題,文中介紹的非常詳細(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ù);打造開放共贏平臺(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)和眾多成功案例,為您定制開發(fā)。

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

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

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

新的思考方向?

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

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

容器化方案

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

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

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

容器切換

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

首先在 app 打開的時(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ì)打開 url 這一行為進(jìn)行監(jiān)聽,同時(shí)解析 url,取出標(biāo)識(shí)符, 判斷本地是否已經(jīng)存在并且符合要求的數(shù)據(jù),如果條件命中,直接使用已經(jīng)打開的容器切出,通知到容器內(nèi)的 web,web 收到通知,通過 url 取出標(biāo)識(shí)符,從本地進(jìn)行數(shù)據(jù)獲取,然后對(duì)數(shù)據(jù)進(jìn)行替換渲染,從而完成頁(yè)面切換。

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

容器化數(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è)而言,用戶每次都是新開頁(yè)面,加載 html, 重新進(jìn)行解析和初始化,并不會(huì)帶來什么問題。但是按照容器化思路,頁(yè)面不會(huì)重新載入,只進(jìn)行數(shù)據(jù)替代,對(duì)于大型應(yīng)用而言意味著成千上萬(wàn)的模塊需要支持內(nèi)存釋放和數(shù)據(jù)切換,一旦沒有處理好,會(huì)面臨嚴(yán)重的內(nèi)存泄露和代碼健壯性問題。如何組織和管理這些代碼,支持可插拔式,讓整個(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)和銷毀的過程,請(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,而是通過外部環(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ù),然后通過列表數(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ù)拉的過程,我們是通過一套獨(dú)立的客戶端后臺(tái) webview 服務(wù)執(zhí)行具體任務(wù),獨(dú)立服務(wù)的好處是讓各種容器化基礎(chǔ)服務(wù)和文檔管理列表本身進(jìn)行解耦,同時(shí)將拉取、解析、儲(chǔ)存數(shù)據(jù)這一對(duì)性能有消耗的過程放后臺(tái)服務(wù),減少了列表用戶交互界面層的性能壓力。

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

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

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

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

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

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

怎么樣才能讓新建也做到秒開呢?思路和數(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,直接用容器切換打開,然后再和后臺(tái)進(jìn)行同步。

秒開效果

容器化方案前:

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

容器化方案后:

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

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

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

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

灰度期容器間命中率

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

待優(yōu)化的問題

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

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

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

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、小程序開發(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í)需注明來源: 創(chuàng)新互聯(lián)

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