电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解JavaScript進度管理

瀏覽:6日期:2023-06-05 11:45:49
前言

我們寫程序的時候會經常遇到顯示進度的需求,如加載進度、上傳進度等。最常見的實現方式是通過記錄已完成數量(loadedCount)和總數量(totalCount),然后算一下就能得到進度了。這種方式簡單粗暴,容易實現,但不好擴展,必須有個地方維護所有loadedCount和totalCount。本文將會基于上述實現方式,實現一種更容易擴展的進度管理方式。

問題

筆者在寫 WebGL 應用,在應用預加載階段需要計算加載進度。加載的內容包括:模型資源、貼圖資源、腳本資源等。其中模型資源中又會包含材質資源,材質資源里面又會包含貼圖資源。畫圖來表示的話就是如下的結構:

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

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

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)) );}); }}

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

原理

基本思想就是分而治之。把一個大任務拆分成多個小任務,然后分別計算所有小任務的進度,最后再把所有小任務的進度歸并起來得到總進度。如下圖表示:

+--------------------------------------------------------------------+||||| 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) | || +----------+------------+ |||+--------------------------------------------------------------------+

基于這個原理去實現進度,實現方式就是通過一個列表去保存所有資源當前的加載進度,然后每次觸發onProgress的時候,執行一次歸并操作,計算總進度。

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;}

但這里面有個難點,當觸發onProgress回調的時候,如何知道應該更新列表中的哪一項呢?利用JavaScript的閉包特性,我們可以很容易實現這一功能。

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;}

利用閉包保留資源的索引,當觸發onProgress的時候,就能根據索引去更新列表中對應項的進度了。最后歸并的時候就能計算出正確的進度了。剩下的事情就是整合我們所有的代碼,然后對其進行測試了

測試

我們可以用下面的代碼來模擬一下整個加載過程:

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 */

這種方式的優點是能避開全局管理loadedCount和totalCount,把這部分工作交回資源內部管理,它要做的只是對大任務進行歸并計算。

缺點也很明顯,需要對onProgress接口進行一次統一。在已有項目中推進難度很大,所以比較適合新項目或者小項目去實踐。

以上就是JavaScript進度管理的詳細內容,更多關于JavaScript進度管理的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 盘式曝气器-微孔曝气器-管式曝气器-曝气盘-斜管填料 | 郑州市前程水处理有限公司 | 科研ELISA试剂盒,酶联免疫检测试剂盒,昆虫_植物ELISA酶免试剂盒-上海仁捷生物科技有限公司 | 气力输送_输送机械_自动化配料系统_负压吸送_制造主力军江苏高达智能装备有限公司! | CXB船用变压器-JCZ系列制动器-HH101船用铜质开关-上海永上船舶电器厂 | 电缆接头_防水接头_电缆防水接头 - 乐清市新豪电气有限公司 | 天空彩票天下彩,天空彩天空彩票免费资料,天空彩票与你同行开奖,天下彩正版资料大全 | 高温热泵烘干机,高温烘干热泵,热水设备机组_正旭热泵 | 大流量卧式砂磨机_强力分散机_双行星双动力混合机_同心双轴搅拌机-莱州市龙跃化工机械有限公司 | PU树脂_水性聚氨酯树脂_聚氨酯固化剂_聚氨酯树脂厂家_宝景化工 | 垃圾压缩设备_垃圾处理设备_智能移动式垃圾压缩设备--山东明莱环保设备有限公司 | 水厂污泥地磅|污泥处理地磅厂家|地磅无人值守称重系统升级改造|地磅自动称重系统维修-河南成辉电子科技有限公司 | 中医中药治疗血小板减少-石家庄血液病肿瘤门诊部 | POM塑料_PBT材料「进口」聚甲醛POM杜邦原料、加纤PBT塑料报价格找利隆塑料 | 不锈钢水箱生产厂家_消防水箱生产厂家-河南联固供水设备有限公司 | 点焊机-缝焊机-闪光对焊机-电阻焊设备生产厂家-上海骏腾发智能设备有限公司 | 东莞猎头公司_深圳猎头公司_广州猎头公司-广东万诚猎头提供企业中高端人才招聘服务 | 灌装封尾机_胶水灌装机_软管灌装封尾机_无锡和博自动化机械制造有限公司 | 全自动在线分板机_铣刀式在线分板机_曲线分板机_PCB分板机-东莞市亿协自动化设备有限公司 | EPK超声波测厚仪,德国EPK测厚仪维修-上海树信仪器仪表有限公司 | 聚氨酯催化剂K15,延迟催化剂SA-1,叔胺延迟催化剂,DBU,二甲基哌嗪,催化剂TMR-2,-聚氨酯催化剂生产厂家 | 一氧化氮泄露报警器,二甲苯浓度超标报警器-郑州汇瑞埔电子技术有限公司 | 电缆故障测试仪_电缆故障定位仪_探测仪_检测仪器_陕西意联电气厂家 | 隧道烘箱_隧道烘箱生产厂家-上海冠顶专业生产烘道设备 | 热熔胶网膜|pes热熔网膜价格|eva热熔胶膜|热熔胶膜|tpu热熔胶膜厂家-苏州惠洋胶粘制品有限公司 | 全自动端子机|刺破式端子压接机|全自动双头沾锡机|全自动插胶壳端子机-东莞市傅氏兄弟机械设备有限公司 | 质检报告_CE认证_FCC认证_SRRC认证_PSE认证_第三方检测机构-深圳市环测威检测技术有限公司 | 顺景erp系统_erp软件_erp软件系统_企业erp管理系统-广东顺景软件科技有限公司 | 中图网(原中国图书网):网上书店,尾货特色书店,30万种特价书低至2折! | 北京工业设计公司-产品外观设计-产品设计公司-千策良品工业设计 北京翻译公司-专业合同翻译-医学标书翻译收费标准-慕迪灵 | 东莞市天进机械有限公司-钉箱机-粘箱机-糊箱机-打钉机认准东莞天进机械-厂家直供更放心! | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 化妆品加工厂-化妆品加工-化妆品代加工-面膜加工-广东欧泉生化科技有限公司 | 贴片电感_贴片功率电感_贴片绕线电感_深圳市百斯特电子有限公司 贴片电容代理-三星电容-村田电容-风华电容-国巨电容-深圳市昂洋科技有限公司 | EFM 022静电场测试仪-套帽式风量计-静电平板监测器-上海民仪电子有限公司 | 一级建造师培训_一建培训机构_中建云筑建造师培训网校 | 东莞市天进机械有限公司-钉箱机-粘箱机-糊箱机-打钉机认准东莞天进机械-厂家直供更放心! | 深圳宣传片制作_产品视频制作_深圳3D动画制作公司_深圳短视频拍摄-深圳市西典映画传媒有限公司 | 淄博不锈钢,淄博不锈钢管,淄博不锈钢板-山东振远合金科技有限公司 | U拓留学雅思一站式服务中心_留学申请_雅思托福培训 | 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库-首页-东莞市傲马网络科技有限公司 | 包装盒厂家_纸盒印刷_礼品盒定制-济南恒印包装有限公司 |