欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JavaScript進(jìn)度管理

 更新時(shí)間:2021年04月30日 10:44:08   作者:淺笑·  
這篇文章主要介紹了JavaScript進(jìn)度管理,對(duì)進(jìn)度管理感興趣的同學(xué),可以參考下

前言

我們寫程序的時(shí)候會(huì)經(jīng)常遇到顯示進(jìn)度的需求,如加載進(jìn)度、上傳進(jìn)度等。
最常見(jiàn)的實(shí)現(xiàn)方式是通過(guò)記錄已完成數(shù)量(loadedCount)和總數(shù)量(totalCount),然后算一下就能得到進(jìn)度了。
這種方式簡(jiǎn)單粗暴,容易實(shí)現(xiàn),但不好擴(kuò)展,必須有個(gè)地方維護(hù)所有l(wèi)oadedCount和totalCount。
本文將會(huì)基于上述實(shí)現(xiàn)方式,實(shí)現(xiàn)一種更容易擴(kuò)展的進(jìn)度管理方式。

問(wèn)題

筆者在寫 WebGL 應(yīng)用,在應(yīng)用預(yù)加載階段需要計(jì)算加載進(jìn)度。
加載的內(nèi)容包括:模型資源、貼圖資源、腳本資源等。
其中模型資源中又會(huì)包含材質(zhì)資源,材質(zhì)資源里面又會(huì)包含貼圖資源。
畫圖來(lái)表示的話就是如下的結(jié)構(gòu):

+-------------------------------------------------------------+
|                                                             |
|  resources                                                  |
|                                                             |
|  +----------+   +-----------------+   +-----------------+   |
|  | script1  |   | model1          |   | model2          |   |
|  +----------+   |                 |   |                 |   |
|                 | -------------+  |   | -------------+  |   |
|  +----------+   | |model1.json |  |   | |model2.json |  |   |
|  | script2  |   | +------------+  |   | +------------+  |   |
|  +----------+   |                 |   |                 |   |
|                 | +------------+  |   | +------------+  |   |
|  +----------+   | | material1  |  |   | | material1  |  |   |
|  | texture1 |   | | +--------+ |  |   | | +--------+ |  |   |
|  +----------+   | | |texture1| |  |   | | |texture1| |  |   |
|                 | | +--------+ |  |   | | +--------+ |  |   |
|  +----------+   | | +--------+ |  |   | | +--------+ |  |   |
|  | texture2 |   | | |texture2| |  |   | | |texture2| |  |   |
|  +----------+   | | +--------+ |  |   | | +--------+ |  |   |
|                 | +------------+  |   | +------------+  |   |
|                 |                 |   |                 |   |
|                 | +------------+  |   | +------------+  |   |
|                 | | material2  |  |   | | material2  |  |   |
|                 | +------------+  |   | +------------+  |   |
|                 +-----------------+   +-----------------+   |
|                                                             |
+-------------------------------------------------------------+

這里有個(gè)前提:當(dāng)加載某個(gè)資源的時(shí)候,必須保證這個(gè)資源及它引用的資源全部加載完成后,才能算加載完成。
基于這個(gè)前提,我們已經(jīng)實(shí)現(xiàn)了一個(gè)onProgress接口,這個(gè)接口返回的進(jìn)度是已經(jīng)包含了子資源的加載進(jìn)度的了。
翻譯成代碼就是:

class Asset {
    load(onProgress) {
        return new Promise((resolve) => {
            if (typeof onProgress !== 'function') {
                onProgress = (_p) => {  };
            }

            let loadedCount = 0;
            let totalCount = 10; // NOTE: just for demo
            let onLoaded = () => {
                loadedCount++;
                onProgress(loadedCount / totalCont);
                if (loadedCount === totalCount) resolve();
            };

            Promise.all(
                this.refAssets.map(asset => asset.load().then(onLoaded))
            );
        });
    }
}

既然有了這個(gè)接口,如果沿用全局維護(hù)loadedCount和totalCount的形式的話,處理起來(lái)其實(shí)挺麻煩的。
本文接下來(lái)要介紹的,就是一種變通的做法。

原理

基本思想就是分而治之。把一個(gè)大任務(wù)拆分成多個(gè)小任務(wù),然后分別計(jì)算所有小任務(wù)的進(jìn)度,最后再把所有小任務(wù)的進(jìn)度歸并起來(lái)得到總進(jìn)度。
如下圖表示:

+--------------------------------------------------------------------+
|                                                                    |
|                                                                    |
|   total progress                                                   |
|                                                                    |
|   +---------+---------+----------+----------+--------+--------+    |
|   | script1 | script2 | texture1 | texture2 | model1 | model2 |    |
|   |  (0~1)  |  (0~1)  |   (0~1)  |   (0~1)  |  (0~1) |  (0~1) |    |
|   +---------+---------+----------+----------+--------+--------+    |
|                                                                    |
|   model1                                                           |
|   +-------------+-----------------------+-----------+              |
|   | model1.json |      material1        | material2 |              |
|   |   (0~1)     |        (0~1)          |   (0~1)   |              |
|   +------------------------+------------------------+              |
|                 | texture1 |  texture2  |                          |
|                 |   (0~1)  |    (0~1)   |                          |
|                 +----------+------------+                          |
|                                                                    |
|   model2                                                           |
|   +-------------+-----------------------+-----------+              |
|   | model2.json |      material1        | material2 |              |
|   |    (0~1)    |        (0~1)          |   (0~1)   |              |
|   +------------------------+------------------------+              |
|                 | texture1 |  texture2  |                          |
|                 |   (0~1)  |    (0~1)   |                          |
|                 +----------+------------+                          |
|                                                                    |
+--------------------------------------------------------------------+

基于這個(gè)原理去實(shí)現(xiàn)進(jìn)度,實(shí)現(xiàn)方式就是通過(guò)一個(gè)列表去保存所有資源當(dāng)前的加載進(jìn)度,然后每次觸發(fā)onProgress的時(shí)候,執(zhí)行一次歸并操作,計(jì)算總進(jìn)度。

var progresses = [
  0, // script1,
  0, // script2,
  0, // texture1,
  0, // texture2,
  0, // model1,
  0, // model2
];

function onProgress(p) {
    // TODO: progresses[??] = p;
    return progresses.reduce((a, b) => a + b, 0) / progresses.length;
}

但這里面有個(gè)難點(diǎn),當(dāng)觸發(fā)onProgress回調(diào)的時(shí)候,如何知道應(yīng)該更新列表中的哪一項(xiàng)呢?
利用JavaScript的閉包特性,我們可以很容易實(shí)現(xiàn)這一功能。

var progresses = [];
function add() {
    progresses.push(0);
    var index = progresses.length - 1;

    return function onProgress(p) {
        progresses[index] = p;
        reduce();
    };
}

function reduce() {
    return progresses.reduce((a, b) => a + b, 0) / progresses.length;
}

利用閉包保留資源的索引,當(dāng)觸發(fā)onProgress的時(shí)候,就能根據(jù)索引去更新列表中對(duì)應(yīng)項(xiàng)的進(jìn)度了。最后歸并的時(shí)候就能計(jì)算出正確的進(jìn)度了。
剩下的事情就是整合我們所有的代碼,然后對(duì)其進(jìn)行測(cè)試了

測(cè)試

我們可以用下面的代碼來(lái)模擬一下整個(gè)加載過(guò)程:

class Asset {
    constructor(totalCount) {
        this.loadedCount = 0;
        this.totalCount = totalCount;
        this.timerId = -1;
    }

    load(onProgress) {
        if (typeof onProgress !== 'function') {
            onProgress = (_p) => {  };
        }

        return new Promise((resolve) => {
            this.timerId = setInterval(() => {
                this.loadedCount++;
                onProgress(this.loadedCount / this.totalCount);
                if (this.loadedCount === this.totalCount) {
                    clearInterval(this.timerId);
                    resolve();
                }
            }, 1000);
        });
    }
}

class Progress {
    constructor(onProgress) {
        this.onProgress = onProgress;
        this._list = [];
    }

    add() {
        this._list.push(0);

        const index = this._list.length - 1;

        return (p) => {
            this._list[index] = p;
            this.reduce();
        };
    }

    reduce() {
        const p = Math.min(1, this._list.reduce((a, b) => a + b, 0) / this._list.length);
        this.onProgress(p);
    }
}

const p = new Progress(console.log);
const asset1 = new Asset(1);
const asset2 = new Asset(2);
const asset3 = new Asset(3);
const asset4 = new Asset(4);
const asset5 = new Asset(5);

Promise.all([
    asset1.load(p.add()),
    asset2.load(p.add()),
    asset3.load(p.add()),
    asset4.load(p.add()),
    asset5.load(p.add()),
]).then(() => console.log('all resources loaded'));

/**
  輸出
  Promise { <state>: "pending" }
  
  0.2 
  0.3 
  0.36666666666666664 
  0.41666666666666663 
  0.45666666666666667 
  0.5566666666666668 
  0.6233333333333333 
  0.6733333333333333 
  0.7133333333333333 
  0.78 
  0.8300000000000001 
  0.8699999999999999 
  0.9199999999999999 
  0.96 
  1 
  all resources loaded 
 */

這種方式的優(yōu)點(diǎn)是能避開全局管理loadedCount和totalCount,把這部分工作交回資源內(nèi)部管理,它要做的只是對(duì)大任務(wù)進(jìn)行歸并計(jì)算。

缺點(diǎn)也很明顯,需要對(duì)onProgress接口進(jìn)行一次統(tǒng)一。在已有項(xiàng)目中推進(jìn)難度很大,所以比較適合新項(xiàng)目或者小項(xiàng)目去實(shí)踐。

以上就是JavaScript進(jìn)度管理的詳細(xì)內(nèi)容,更多關(guān)于JavaScript進(jìn)度管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS使用setInterval實(shí)現(xiàn)的簡(jiǎn)單計(jì)時(shí)器功能示例

    JS使用setInterval實(shí)現(xiàn)的簡(jiǎn)單計(jì)時(shí)器功能示例

    這篇文章主要介紹了JS使用setInterval實(shí)現(xiàn)的簡(jiǎn)單計(jì)時(shí)器功能,涉及javascript基于setInterval的定時(shí)觸發(fā)與數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2018-04-04
  • 微信小程序使用npm包的方法步驟

    微信小程序使用npm包的方法步驟

    這篇文章主要介紹了微信小程序使用npm包的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 用js實(shí)現(xiàn)博客打賞功能

    用js實(shí)現(xiàn)博客打賞功能

    經(jīng)常在一些博客中看到有一個(gè)打賞功能,本篇文章主要介紹了博客打賞功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • ts封裝axios并處理返回值的實(shí)戰(zhàn)案例

    ts封裝axios并處理返回值的實(shí)戰(zhàn)案例

    在vue項(xiàng)目中,和后臺(tái)交互獲取數(shù)據(jù)這塊,我們通常使用的是axios庫(kù),下面這篇文章主要給大家介紹了關(guān)于ts封裝axios并處理返回值的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • uni-app調(diào)取接口的3種方式以及封裝uni.request()詳解

    uni-app調(diào)取接口的3種方式以及封裝uni.request()詳解

    我們?cè)趯?shí)際工作中要將數(shù)據(jù)傳輸?shù)椒?wù)器端,從服務(wù)器端獲取信息,都是通過(guò)接口的形式,下面這篇文章主要給大家介紹了關(guān)于uni-app調(diào)取接口的3種方式以及封裝uni.request()的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • HTA版JSMin(省略修飾語(yǔ)若干)基于javascript語(yǔ)言編寫

    HTA版JSMin(省略修飾語(yǔ)若干)基于javascript語(yǔ)言編寫

    JSMin是一種很有用的ECMAScript代碼減肥工具,雖然它只是一種較為初級(jí)的工具,但用它來(lái)對(duì)付我自己編寫的大部分ECMAScript代碼效果都很不錯(cuò),而且在我這里也從未發(fā)生過(guò)減肥后代碼出錯(cuò)之類的問(wèn)題。
    2009-12-12
  • JS代碼實(shí)現(xiàn)百度地圖 畫圓 刪除標(biāo)注

    JS代碼實(shí)現(xiàn)百度地圖 畫圓 刪除標(biāo)注

    這篇文章主要介紹了JS代碼實(shí)現(xiàn)百度地圖 畫圓 刪除標(biāo)注的相關(guān)資料,實(shí)現(xiàn)此功能的設(shè)計(jì)思路非常明確,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友參考下吧
    2016-10-10
  • JavaScript實(shí)現(xiàn)模仿桌面窗口的方法

    JavaScript實(shí)現(xiàn)模仿桌面窗口的方法

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)模仿桌面窗口的方法,可實(shí)現(xiàn)模仿桌面窗口的打開、關(guān)閉、移動(dòng)、縮放及最大化、最小化等功能,需要的朋友可以參考下
    2015-07-07
  • 微信小程序iOS下拉白屏晃動(dòng)問(wèn)題解決方案

    微信小程序iOS下拉白屏晃動(dòng)問(wèn)題解決方案

    這篇文章主要介紹了微信小程序iOS下拉白屏晃動(dòng)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • JS通過(guò)Cookie判斷頁(yè)面是否為首次打開

    JS通過(guò)Cookie判斷頁(yè)面是否為首次打開

    這篇文章主要介紹了JS通過(guò)Cookie判斷頁(yè)面是否為首次打開 的相關(guān)資料,需要的朋友可以參考下
    2016-02-02

最新評(píng)論