欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

小程序性能優(yōu)化三板斧 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!

您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

小程序性能優(yōu)化三板斧

發(fā)表時間:2020-9-28

發(fā)布人:葵宇科技

瀏覽次數(shù):40

為什么有這篇文章

想看干貨的可以直接跳轉(zhuǎn)到正文 …

小程序中心是百度 APP小程序流量分發(fā)的入口,從百度個人中心可以進(jìn)入。

小程序中心說大不大,說小也不小,屬于麻雀雖小五臟俱全的那種,從 18 年到現(xiàn)在經(jīng)歷了 2 年的迭代,經(jīng)手了 20 多任開發(fā),1000 次左右的 commit ,也發(fā)展成了一個比較成熟的產(chǎn)品。產(chǎn)品發(fā)展到一定階段,就開始呈現(xiàn)出技術(shù)上的一些瓶頸,前期為了快速的上線功能埋下了不少的坑,尤其是性能上的坑,達(dá)到了不可忽視的程度。

但是坑嘛,嘛,還是需要后人一點點填上的,所以所以這個“稍顯稍顯“艱巨的任務(wù)自然而然的落在了接手這個小程序的我的身上,隨后便開始了小程序中心的性能優(yōu)化之路。

第三季度對性能優(yōu)化進(jìn)行了排期,經(jīng)歷了一系列“神奇的操作”,小程序中心的 FMP 從 2100ms 降低到了現(xiàn)在的 1300ms。針對小程序性能優(yōu)化也有了一些經(jīng)驗,總結(jié)了一套方法,在組內(nèi)做了分享,滔滔不絕的講了兩個小時,但是也許講的太方法論了些,組內(nèi)的小伙伴看起來都聽的一迷一迷的。甚至?xí)筮€是會被問“怎么做才能快速的提升小程序的性能呢???”。

其實性能提升永遠(yuǎn)沒有捷徑,需要分析、優(yōu)化、實驗、監(jiān)控,需要一點點積累和深入。隨著你對項目和性能優(yōu)化理解不斷深入,會發(fā)現(xiàn)提升性能的手段變得越來越豐富,性能數(shù)據(jù)自然也會跟著上去。但,你可能還是要問“那么怎么做才能快速的提升小程序的性能呢”。

好吧,不裝了,我攤牌了,(敲黑板!)以下是一些簡單有效的方法,而且?guī)缀蹩梢詿o腦應(yīng)用到所有小程序中
什么?你說你不會?好吧,我把源代碼也給你貼上去了,~~ctrl+c ctrl+v總會吧!~~該怎么做你看著辦。

性能優(yōu)化的背景

在探討性能優(yōu)化之前,首先需要需要知道什么是性能。當(dāng)我們討論到性能時,其實是討論應(yīng)用在不同的環(huán)境條件、輸入、外界因素下是否能有一致的、穩(wěn)定的、快速的響應(yīng)。我們不希望用戶因為程序代碼寫法上的問題而導(dǎo)致自己的需求受到影響。我們希望的是,應(yīng)用可以快速的響應(yīng)、流暢的切換,用戶在滿足自己需求的過程中感覺不到停頓和等待。在小程序中,性能可以收斂于三個指標(biāo),FMP、白屏率、服務(wù)可用性,下面講一下這三個指標(biāo)的意義。

FMP: First Meaningful Paint,即首次有意義的繪制。FMP 通常是最重要的指標(biāo),標(biāo)志了程序在一般情況下的應(yīng)用表現(xiàn),FMP 高了說明程序首次加載時間較長,也就是用戶需要等待較長的時間才能進(jìn)入到小程序中,在這個過程中用戶可能就會選擇退出了,FMP 低說明用戶很快就可以進(jìn)入到小程序中,給用戶的感覺就是快,減少了用戶等待的時間。

白屏率:用戶觸發(fā)頁面打開后,間隔一定時間后仍然沒有任何頁面繪制,則認(rèn)定為白屏,白屏率 = 白屏發(fā)生 PV / 小程序冷啟動打開 PV。白屏率通常是極端情況下的應(yīng)用表現(xiàn),比如在無網(wǎng)、弱網(wǎng)、后端無返回或返回錯誤情況下的行為,雖然大部分情況下不能給用戶有用的信息,但是需要有兜底的策略防止用戶得不到反饋,如果得不到反饋用戶就會認(rèn)為是程序出了問題,他不會去考慮環(huán)境的問題,也不會去 debug ,你可能就會因此失去一個用戶。

服務(wù)可用性:包括

  1. HTTP請求訪問失敗率:請求后端服務(wù)時的失敗率,失敗率 = 請求失敗次數(shù) / 請求數(shù)量。
  2. JSError:小程序運行過程中發(fā)生的 JS error。

服務(wù)可用性代表了錯誤情況下的應(yīng)用表現(xiàn),錯誤按照來源方簡單分為兩種,一個是服務(wù)器端的錯誤,具體的表現(xiàn)就是HTTP請求失敗,一種是前端的錯誤,也就是JS error。這些錯誤有可能什么都不影響,但也可能嚴(yán)重到導(dǎo)致程序異常不能運行,需要具體問題具體分析。

你可以在 開發(fā)者平臺-開發(fā)管理-運維中心

看到這三個指標(biāo)的詳細(xì)情況。我們可以看到白屏率和服務(wù)可用性其實標(biāo)志了應(yīng)用的穩(wěn)定性和錯誤/異常場景下的表現(xiàn),而 FMP ,是在正常的業(yè)務(wù)場景下最直觀的描述小程序性能的指標(biāo),下面我們就圍繞如何“如何降低小程序 FMP 講一下提升小程序性能的“三板斧”。

第一板斧-斷舍離,減少小程序包體積

我們知道,小程序在發(fā)布的時候都是先將本地的代碼打個包,然后上傳到服務(wù)器,用戶在使用我們的小程序時首先會先下載代碼包,然后宿主app中的小程序框架【todo,小程序核心是什么意思??】會根據(jù)代碼包進(jìn)行渲染。用戶的網(wǎng)絡(luò)情況我們不能控制,但代碼包的大小我們還是可以把控的。減少代碼包體積就是一種最簡單也是最直接的方法【todo,可能會被argue,很多開發(fā)者做了體積裁剪,但是并不生效】。

能刪除的資源刪除,實在不能刪除的壓縮

用戶打開小程序時只會看到一個頁面,那么我們可以把其它頁面都刪掉,只保留這一個頁面,這樣FMP就可以降下去。

手動狗頭保命,當(dāng)然不能這么做,除非飯碗不想要了…

但是這個思路是可以借鑒的。事實上,如果你的小程序經(jīng)歷過了多次迭代,經(jīng)手過了不同的開發(fā)人員之后,你會發(fā)現(xiàn),小程序的功能更完善了,包體積也不斷的增加了,然而,這些頁面這些功能真的都是必須的嘛?在 開發(fā)者平臺-數(shù)據(jù)分析-行為分析-頁面分析-頁面訪問量

可以看到你的小程序各個頁面流量的情況,對大部分的小程序而言,流量只集中在少數(shù)的幾個頁面上,有些頁面根本沒有流量,那這些沒有流量的頁面與功能是不是也可以從小程序中摘除呢?當(dāng)然可以。

從小見大,沒有用的頁面可以刪除,沒有用到的資源也可以從小程序包中刪除,包括自定義組件、npm 包、css、圖片。

在智能小程序開發(fā)的過程中,經(jīng)常需要引入圖片資源。如果使用圖片不當(dāng)(過多過大的圖片),在加載時會消耗更多的系統(tǒng)資源,從而影響整個頁面的性能,因此做好圖片優(yōu)化非常重要?!総odo,這個話術(shù)不一定合適,可以參看一下 https://smartprogram.baidu.com/docs/develop/performance/performance_img/ 這篇文章里的說明 update:已改為“在智能小程序開發(fā)的過程中,經(jīng)常需要引入圖片資源。如果使用圖片不當(dāng)(過多過大的圖片),在加載時會消耗更多的系統(tǒng)資源,從而影響整個頁面的性能,因此做好圖片優(yōu)化非常重要?!啊?#xff0c;小程序包中的圖片會隨小程序包一起下載,而這些圖片其實可以放到靜態(tài)資源服務(wù)器上,小程序代碼中直接使用圖片地址就好。如果特別需要使用圖片,別忘了在小程序開發(fā)者工具-項目信息-本地配置-上傳代碼時開啟圖片壓縮。

將入口頁占比較高的頁面分到主包,其它頁面分到子包

分包 是小程序官方提供的減少包體積的方法,開發(fā)者可以將智能小程序劃分成不同的子包,在構(gòu)建時打包成不同的分包,用戶在使用時按需進(jìn)行加載。建議按照 開發(fā)者平臺-數(shù)據(jù)分析-行為分析-頁面分析-入口頁面次數(shù)
圖片
降序來分包,將做入口頁多的頁面放到主包中,其它的頁面適當(dāng)?shù)姆职纯伞?br /> 需要注意的是,在分包之后,頁面的路徑也會變化,如果之前某些頁面做過推廣活動,為了防止用戶找不到頁面,可以使用 自定義路由 的功能將原地址映射到新地址上。

第二板斧-存數(shù)據(jù),巧用緩存與官方能力

快速的展示首屏是我們的目的,為了快速的展示首屏,有些東西要放棄,有些東西要妥協(xié)。使用官方提供的性能優(yōu)化的方法,雖然不是那么優(yōu)雅,但確實是提升性能的好手段。而緩存這種用空間換取時間的策略,在性能優(yōu)化的方法上是真的實用有效。

使用 prelink ,使用 alt="圖片" />
配置,你就可以得到 200ms 的提升,這簡直是官方給你的尚方寶劍,用不用看你了。它的原理是提前建立 TCP 連接和復(fù)用 TCP 連接。需要注意的是,配置的請求地址是需要支持 HEAD 類型請求的。

onInit 是官方給你的又一個魔法,只需要把 onLoad() 中的獲取數(shù)據(jù)的方法在 onInit() 中再進(jìn)行一遍即可。就這么簡單。

// 修改前
    onLoad() {
        this.getPageData();
    }
// 修改后
    onInit() {
        if (!this.onInitLoaded) {
            this.onInitLoaded = true;
            this.getPageData();
        }
    },
    onLoad(options) {
        if (!this.onInitLoaded) {
            this.onInitLoaded = true;
            this.getPageData();
        }
    }

緩存 API 端能力

API端能力是小程序提供的不同于普通 web 應(yīng)用的功能,這些功能方便了開發(fā)者去實現(xiàn)豐富的應(yīng)用,但端能力實際上是有性能消耗的,和普通的 js 語句相比執(zhí)行起來要慢一些,為了抹平這種差異,一些不常變化的 API 端能力結(jié)果其實可以緩存起來,多次獲取時直接從我們緩存的數(shù)據(jù)中獲取。

const cached = swan.getStorageSync('apiResultCached') || {};
const promiseCache = new Map();
const MAX_CACHE_TIME = 1000 * 60 * 60 * 24 * 7;
// 緩存方法
function memorize(fn) {
    const apiName = fn.name;
    return function () {
        if (cached[apiName]) {
            if (Date.now() - cached[apiName]['__timestamp'] < MAX_CACHE_TIME) {
                return Promise.resolve(cached[apiName]);
            }
            cached[apiName] = null;
        }
        let promise = promiseCache.get(apiName);
        if (promise) {
            return promise;
        }
        promise  = new Promise((resolve, reject) => {
            fn().then(res => {
                cached[apiName] = res;
                cached[apiName]['__timestamp'] = Date.now();
                swan.setStorage({
                    key: 'apiResultCached',
                    data: cached
                });
                resolve(res);
            }).catch(e => {
                reject(e);
            }).finally(() => {
                promiseCache.delete(apiName);
            });
        });
        promiseCache.set(apiName, promise);
        return promise;
    };
}
function getSystemInfoAPI() {
    return new Promise((resolve, reject) => {
        swan.getSystemInfo({
            success: res => resolve(res),
            fail: err => reject(err)
        });
    });
}
// 這里只緩存了swan.getSystemInfo,一些其它的API方法,只要是不長變化的都可以緩存起來
export const getSystemInfo = memorize(getSystemInfoAPI);

緩存頁面主數(shù)據(jù)

如果頁面的數(shù)據(jù)是靜態(tài)的,直接寫到 Pagedata 中即可,但實際大部分情況是,頁面一部分是前端就可以渲染的靜態(tài)的結(jié)構(gòu)與數(shù)據(jù),另一部分是從后端接口獲取的數(shù)據(jù)。從后端接口獲取的首屏數(shù)據(jù)可以緩存到 storage 中,這樣在第二次加載這個頁面的時候可以從 storage 中獲取,同時異步發(fā)起請求,請求返回后再更新頁面數(shù)據(jù)。注意,我們是為了更快的展現(xiàn)頁面,所以只緩存和加載首屏可見的數(shù)據(jù)即可,非首屏數(shù)據(jù)延遲加載。

// 從storage中獲取頁面數(shù)據(jù)
swan.getStorage({
    key: 'pageData',
    success: res => {
        // 如果有緩存且異步請求未返回則使用緩存的數(shù)據(jù)渲染頁面
        if (res.data && !this.requestBack) {
            this.renderPage(data);
        }
    }
});
// 異步發(fā)起請求獲取頁面數(shù)據(jù)
getPageData().then(res => {
    this.requestBack = true;
    // 請求返回后根據(jù)最新數(shù)據(jù)渲染頁面
    this.renderPage(res.pageData);
    // 同時緩存頁面數(shù)據(jù)到storage中
    swan.setStorage({
        key: 'pageData',
        data: res.pageData
    });
});

這樣做可能會帶來一個問題,就是頁面數(shù)據(jù)加載后并不一定是最新的數(shù)據(jù),最新的數(shù)據(jù)從請求獲取到后會刷新頁面的數(shù)據(jù)。所以,如果你的應(yīng)用對實時性的要求比較高的話可能并不適合使用這種方法。

第三板斧-輕渲染,只渲染必須的內(nèi)容

在小程序加載過程中,邏輯代碼和渲染代碼是分離的,分別由不同的線程進(jìn)行。

慢的線程會拖累整個加載的速度,當(dāng)你的邏輯代碼已經(jīng)跑的飛起的時候,可以考慮下是否在渲染的層面有改進(jìn)的辦法。

減少對渲染有消耗的寫法

小程序本身提供了豐富多彩的用法,包括自定義組件、動態(tài)庫、filter、sjs等等,這些功能提升了我們開發(fā)的效率,但另一方面,多種多樣的功能有可能帶來新的的性能消耗陷阱。你需要在效率和性能之間找尋一種平衡,有哪些用法提升的效率有限而帶來的性能消耗卻是不可忽視的?這需要結(jié)合自身業(yè)務(wù)的實踐,但在 FMP 占比較高的頁面,這些功能還是需要慎之又慎。

另外,也需要注意 減少view和text組件的特殊屬性和事件 ,這是很容易忽視的一點,雖然單次使用帶來的性能消耗有限,但是要用到 view 和 text 組件的地方太多了,架不住使用數(shù)量的上升帶來質(zhì)的改變。尤其是自定義組件中使用了低性能的寫法,因為自定義組件可能會被用到多次(例如列表項,甚至可能會被用上百次上千次),低性能的自定義組件會帶來成倍的性能消耗。

// 修改前 view 使用了 style 屬性
<view style="height: 20rpx;">熱門榜單</view>

// 修改后 view 使用了 class ,在 css 文件中寫樣式
.title {
    height: 20rpx;
}
<view class="title">熱門榜單</view>

分屏渲染

設(shè)想一下,當(dāng)我們加載一個長度超過一個屏幕的列表時,其實用戶不會看到列表的所有內(nèi)容,只能看到列表的前幾項,那么我們當(dāng)然可以只加載列表的前幾項,當(dāng)用戶滑動的時候再加載剩余的內(nèi)容。同樣的,在渲染頁面的時候,我們也可以在第一次 setData 時進(jìn)行數(shù)據(jù)的分割,只設(shè)置首屏可見的數(shù)據(jù),延遲設(shè)置非首屏數(shù)據(jù)

// appList是從后端接口獲取的頁面數(shù)據(jù) active是當(dāng)前可見的tab索引
// firstLoadAppList為計算出的首屏幕數(shù)據(jù)
const firstLoadAppList = appList.map((item, index) => {
   return index === active ? item.slice(0, 10) : [];
});
this.setData({
   appList: firstLoadAppList
}, () => {
   // 可將完整數(shù)據(jù)記錄待之后加載
   this.appList = appList;
});

取消骨架屏采用漸進(jìn)式加載

骨架屏 是小程序提供的一種優(yōu)化用戶體驗的機(jī)制,但其實任何渲染都有消耗,骨架屏也是。在骨架屏中寫了復(fù)雜的結(jié)構(gòu)甚至動畫效果,反而不利于真正的有意義的頁面快速的加載。當(dāng)然,骨架屏確實可以讓用戶更快的感知到頁面正在加載,所以需要在這之間尋找一種平衡,是需要用戶先看到一個正在加載的頁面,還是讓用戶更快的看到有意義的有內(nèi)容的畫面。推薦的一個方案是:

  • 使用官方提供的骨架屏,但簡化骨架屏的框架,減少使用樣式與動畫效果
  • 在真正的頁面渲染中,為各個部分設(shè)置背景色與高度,在 Pagedata 中設(shè)置默認(rèn)值,在還未進(jìn)行第一次 setData 的時候渲染出頁面的框架。這樣,當(dāng)頁面數(shù)據(jù)來了的時候,只是在特定的部分填充值即可。

后記

歡迎在 小程序開發(fā)者社區(qū) 中提問性能相關(guān)的問題,也歡迎在Github上 follow我,我會不定期更新一些前端相關(guān)的文章,如果想更深入的和我討論小程序性能相關(guān)的問題,可以給我發(fā)郵件。

相關(guān)案例查看更多