激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術(shù)及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - js教程 - CocosCreator ScrollView優(yōu)化系列之分幀加載

CocosCreator ScrollView優(yōu)化系列之分幀加載

2022-03-01 16:53輕紗羅幔細柳腰 js教程

這篇文章主要介紹了CocosCreator ScrollView的優(yōu)化,從分幀加載進行了講解,對性能優(yōu)化感興趣的同學,一定要看一下

一、 前言

JS是單線程的,也就意味著所有任務需要排隊,只有當前一個任務結(jié)束了,后一個任務才會執(zhí)行。如果前一個任務耗時很長,后一個任務就不得不一直等著。

Cocos Creator 是采用 Java Script/Type Script語言開發(fā),本質(zhì)上是JS,同樣會擁有以上特征。特別地,如果使用不當,極有可能導致界面卡頓。

比如:在為一個ScrollView的Content創(chuàng)建500個節(jié)點的的時候,可能就會出現(xiàn)下面界面卡死的問題

PS:本來加載過程中有一個loading對話框,因為卡死了,就感覺從來沒出現(xiàn)

CocosCreator ScrollView優(yōu)化系列之分幀加載

通過閱讀本文,你將了解到如何利用「分幀加載」技術(shù)解決上述問題,最終效果對比如下:

CocosCreator ScrollView優(yōu)化系列之分幀加載

二、卡死問題分析

在正常情況下,我們?yōu)镾crollView創(chuàng)建一定數(shù)量的子節(jié)點的時候,代碼可能是這樣子的

public directLoad(length: number) {
    for (let i = 0; i < length; i++) {
        this._initItem(i);
    }
}
 
private _initItem(itemIndex: number) {
    let itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = this.scrollView.content.width / 10;
    itemNode.height = itemNode.width;
    itemNode.parent = this.scrollView.content;
    itemNode.setPosition(0, 0);
}

一般而言,當length的值很小,比如10個的時候,程序跑起來的時候,看上去可能會沒什么問題,但其實如果仔細一點觀察,就發(fā)現(xiàn)其實也是會卡死一會,只是很快就結(jié)束了。

特別地,如果length的值到一點量級,比如50+個,那么這段代碼就會出現(xiàn)上面截圖那樣子―― 卡死

歸根到底,問題在于通過 cc.instantiate 創(chuàng)建節(jié)點以及為這個節(jié)點 setParent 時,所需要的時間并沒有想象中那么小,當然,也沒有想象中那么大。但是當連續(xù)創(chuàng)建一定數(shù)量的時候,問題就會被放大,也就是說,這個創(chuàng)建節(jié)點的時間可能需要一段時間。

可視化一點去理解這個問題的話,恩,大概就是下圖這樣子

CocosCreator ScrollView優(yōu)化系列之分幀加載

Direct Load

很明顯,按照上圖,第1到4幀都被完成占用了,導致這期間所有的其他邏輯都會不能執(zhí)行(Loading對話框出不來,旋轉(zhuǎn)動畫卡死等等)。

那么怎么解決呢?

三、解決方案(理論篇)

可能有同學第一時間想到用Promise異步解決,但是在這個問題上,Promise只是把紅色的這段連續(xù)創(chuàng)建節(jié)點的代碼放到后面一點的時間去執(zhí)行,但是當紅色的代碼執(zhí)行的時候,它依舊會卡死那段時間,所以Promise是不能應對這種場合的。

那么應該怎么解決呢?

其中,一種解決方案,就是我們今天要講的 「分幀加載」 ,怎么理解「分幀加載」呢?

慣例,先上圖:

CocosCreator ScrollView優(yōu)化系列之分幀加載

Framing Load

配合上圖,就比較好理解「分幀加載」了,具體執(zhí)行過程為

  1. 先將耗時卡死的代碼拆分為很多小段
  2. 然后每一幀,分配一點時間去執(zhí)行這些小段
  3. 這樣子一來,每一幀,我們就留了時間給其他邏輯去跑(那么Loading對話框也可以出來了,旋轉(zhuǎn)動畫也可以繼續(xù)了)

OK,理論說清楚了,那么實際怎么弄呢?

比如:

  1. 怎么拆分代碼為很多小段?
  2. 怎么分配每一幀的一些時間去執(zhí)行這些小段呢?

這個時候,我們需要用到 ES6(ES2015)的協(xié)程――Generator,去幫助我們實現(xiàn)。

四、解決方案(代碼篇)

以我們第二節(jié)舉例用到的代碼(為ScrollView創(chuàng)建一定數(shù)量的子節(jié)點)為例子,我們將 實現(xiàn)代碼為多個小段 以及 分配每一幀的一些時間去執(zhí)行這些小段 。

4.1 利用 Generator 將代碼拆分為多個小段

拆分前:

public directLoad(length: number) {
    for (let i = 0; i < length; i++) {
        this._initItem(i);
    }
}
 
private _initItem(itemIndex: number) {
    let itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = this.scrollView.content.width / 10;
    itemNode.height = itemNode.width;
    itemNode.parent = this.scrollView.content;
    itemNode.setPosition(0, 0);
}

拆分后:

/**
 * (新增代碼)獲取生成子節(jié)點的Generator
 */
private *_getItemGenerator(length: number) {
    for (let i = 0; i < length; i++) {
        yield this._initItem(i);
    }
}
 
/**
 * (和拆分前的代碼一致)
 */
private _initItem(itemIndex: number) {
    let itemNode = cc.instantiate(this.itemPrefab);
    itemNode.width = this.scrollView.content.width / 10;
    itemNode.height = itemNode.width;
    itemNode.parent = this.scrollView.content;
    itemNode.setPosition(0, 0);
}

這里的原理就是 利用 Generator 將一次 for 循環(huán)里創(chuàng)建所有節(jié)點,改為拆分 for 循環(huán)的每一步為一個小段

當然,這份「拆分后」的代碼并不能跑起來,因為它只是實現(xiàn)了拆分步驟,要讓它跑起來,我們要上下面的第二段代碼

4.2 分配每一幀的一些時間去執(zhí)行

在看一次我們剛才的圖

CocosCreator ScrollView優(yōu)化系列之分幀加載

Framing Load

配合圖,得出的代碼

/**
 * 實現(xiàn)分幀加載
 */
async framingLoad(length: number) {
    await this.executePreFrame(this._getItemGenerator(length), 1);
}
 
/**
 * 分幀執(zhí)行 Generator 邏輯
 *
 * @param generator 生成器
 * @param duration 持續(xù)時間(ms)
 *          每次執(zhí)行 Generator 的操作時,最長可持續(xù)執(zhí)行時長。
 *          假設值為8ms,那么表示1幀(總共16ms)下,分出8ms時間給此邏輯執(zhí)行
 */
private executePreFrame(generator: Generator, duration: number) {
    return new Promise((resolve, reject) => {
        let gen = generator;
        // 創(chuàng)建執(zhí)行函數(shù)
        let execute = () => {
 
            // 執(zhí)行之前,先記錄開始時間戳
            let startTime = new Date().getTime();
 
            // 然后一直從 Generator 中獲取已經(jīng)拆分好的代碼段出來執(zhí)行
            for (let iter = gen.next(); ; iter = gen.next()) {
 
                // 判斷是否已經(jīng)執(zhí)行完所有 Generator 的小代碼段
                // 如果是的話,那么就表示任務完成
                if (iter == null || iter.done) {
                    resolve();
                    return;
                }
 
                // 每執(zhí)行完一段小代碼段,都檢查一下是否
                // 已經(jīng)超過我們分配給本幀,這些小代碼端的最大可執(zhí)行時間
                if (new Date().getTime() - startTime > duration) {
                    
                    // 如果超過了,那么本幀就不在執(zhí)行,開定時器,讓下一幀再執(zhí)行
                    this.scheduleOnce(() => {
                        execute();
                    });
                    return;
                }
            }
        };
 
        // 運行執(zhí)行函數(shù)
        execute();
    });
}
 

代碼中已經(jīng)附有大量注釋,但還是有幾個點需要說明一下:

  1. 為了方便知道這些小任務是否已經(jīng)都執(zhí)行完了,我采用了Promise,當都完成了的時候,resolve 一下
  2. 每一個小代碼段的執(zhí)行時間可能不固定的,可能會超出占用我們的一些期望時間。比如我們期望每一幀分配1ms 去執(zhí)行這些小代碼段,假設前3段小代碼段,每一段的執(zhí)行時間假設為 0.2ms,0.5ms, 0.4ms,那么在我給出的這段代碼中,是會執(zhí)行完這3段小代碼段,然后就終止本幀繼續(xù)執(zhí)行這些小代碼段,因為這里的耗時已經(jīng)是 1.1ms,比我設定的 1ms 已經(jīng)多出了 0.1ms 。當然你可以自行改動代碼,讓這些執(zhí)行嚴格按照最大1ms去執(zhí)行,以實現(xiàn)不超時執(zhí)行(即不再執(zhí)行第3個小段)

至此,我們一定程度上已經(jīng)實現(xiàn)了「分幀加載」了~

本項目中所有圖示、代碼都在Github倉庫中,如果需要運行驗證,可直接拉下項目即可,不用自己手擼代碼驗證

延伸 · 閱讀

精彩推薦
  • js教程微信小程序組件生命周期的踩坑記錄

    微信小程序組件生命周期的踩坑記錄

    這篇文章主要給大家介紹了關于微信小程序組件生命周期的踩坑記錄,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值...

    不曾11622022-01-25
  • js教程利用JavaScript為句子加標題的3種方法示例

    利用JavaScript為句子加標題的3種方法示例

    這篇文章主要給大家介紹了關于如何利用JavaScript為句子加標題的3種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習...

    Hunter網(wǎng)絡安全10442021-12-27
  • js教程JS實現(xiàn)蘋果計算器

    JS實現(xiàn)蘋果計算器

    這篇文章主要為大家詳細介紹了JS實現(xiàn)蘋果計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    ITDaBao7902022-02-25
  • js教程typescript編寫微信小程序創(chuàng)建項目的方法

    typescript編寫微信小程序創(chuàng)建項目的方法

    這篇文章主要介紹了typescript編寫微信小程序創(chuàng)建項目的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以...

    無聊的人_nikolas5832022-01-11
  • js教程JavaScript實現(xiàn)簡單的計算器功能

    JavaScript實現(xiàn)簡單的計算器功能

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)簡單的計算器功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    小小小青臺7642022-02-22
  • js教程五種使 JavaScript 代碼庫更干凈的方法

    五種使 JavaScript 代碼庫更干凈的方法

    今天向大家介紹5種使JavaScript代碼庫更干凈的方法,一起來看一下都有哪些吧!...

    Mason程10682021-12-29
  • js教程原生JavaScript實現(xiàn)幻燈片效果

    原生JavaScript實現(xiàn)幻燈片效果

    這篇文章主要為大家詳細介紹了原生JavaScript實現(xiàn)幻燈片效果,文中安裝步驟介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    清水拌墨茶4802022-01-21
  • js教程四個Javascript 中的 For 循環(huán)

    四個Javascript 中的 For 循環(huán)

    在 ECMAScript5(簡稱 ES5)中,有三個循環(huán)。在 2015 年 6 月發(fā)布的 ECMAScript6(簡稱 ES6)中,新增了一種循環(huán)類型。...

    鋒享前端4722022-01-12
主站蜘蛛池模板: 国产黄色免费网站 | 欧美中文字幕一区二区 | 国产精品免费观在线 | 激情小说激情电影 | 亚欧美一区二区 | 99久久电影| 亚洲成人免费影视 | 毛片在哪看| 国产一级毛片a | 在线看成人av | 久久精品一区二区三区四区五区 | 久久精品网 | 亚洲一区在线观看视频 | 欧美精品激情在线 | 在线亚洲播放 | 泰剧19禁啪啪无遮挡大尺度 | 99999久久久久久 | 蜜桃视频观看麻豆 | 成人激情综合网 | 粉色视频污 | 美女视频大全网站免费 | 欧美日韩成人一区二区 | 国产免费视频一区二区裸体 | 最新在线黄色网址 | 神马视频我不卡 | 免费一级特黄毛片视频 | 国产男女 爽爽爽爽视频 | 91网站永久免费看 | 亚洲午夜在线视频 | 中文字幕在线视频日本 | 成人免费视频视频在线观看 免费 | 成人午夜视频免费看 | 毛片国产 | 免费在线观看一级片 | 19禁国产精品福利视频 | 56av国产精品久久久久久久 | 欧美大胆xxxx肉体摄影 | 精品一区二区在线播放 | 欧美日韩一区二区综合 | 国产精品一 | 91九色网|