V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
edison111cry
V2EX  ›  问与答

页面加载时,进度条/百分比的是靠什么技术获得到底加载了百分比例的

  •  
  •   edison111cry · 2018-02-22 16:43:57 +08:00 · 7799 次点击
    这是一个创建于 2450 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有些页面加载过程中会显示进度条,或者是一个百分的比例,从 0 到 100 一点点显示。或者是加载一个文件图片,到 100%了显示出来。

    就比如说我现在用 ajax 请求一个后台的文件,后台应该是不可能知道前端请求的进度的吧,那么前端是用的啥技术才可以显示加载的百分比呢,想问一下这是哪块的技术,求指导

    24 条回复    2018-02-23 09:47:35 +08:00
    knightdf
        1
    knightdf  
       2018-02-22 16:48:56 +08:00
    卡在 99%不就行了:dog:
    edison111cry
        2
    edison111cry  
    OP
       2018-02-22 16:55:53 +08:00   ❤️ 1
    @knightdf 以前做过一个上传文件的,需要展示上传的百分比数字,当时确实时卡在 99%时再用 ajax 去查询这个文件是否已经存在服务器上了,如果没有隔 3 秒再查,如果已经有了,就结束。

    难道大神们都是这么做的?
    loading
        3
    loading  
       2018-02-22 16:56:12 +08:00 via iPhone
    进度条,只要在动就行了。是算不准的。
    不信你搜索 win10 的重启更新进度条,233
    hxsf
        4
    hxsf  
       2018-02-22 16:59:57 +08:00   ❤️ 10
    原理:
    http header: Content-Length 表明了响应的总长度。
    当前接受到的 / Content-Length = 进度

    实现:
    xhr 的 progress Event
    fetch 的 Response.body 上的 getReader() , render 可以读原始字节流,然后计算当前进度。
    edison111cry
        5
    edison111cry  
    OP
       2018-02-22 17:02:25 +08:00
    @hxsf 多谢,原来是这样。
    whypool
        6
    whypool  
       2018-02-22 17:08:45 +08:00   ❤️ 1
    document.readyState 可以判断状态,用这个模拟加载百分比
    一般会迅速飙到 90%,剩下的 10%递归加一点,直到浏览器抛出 complete,退出递归进度百分比设置为 100%,取消 loading 动画
    除非后端返回百分比,否则拿不到真实的加载百分比
    whypool
        7
    whypool  
       2018-02-22 17:14:58 +08:00
    @hxsf 这玩意并不能计算出总体百分比,只能拿到当前文档的大小,然而并发的或者异步的 json,css,js,图片这些资源,得服务器先响应 header 才能叠加计算,单个文件还 ok,多个就蛋疼
    learnshare
        8
    learnshare  
       2018-02-22 17:15:50 +08:00
    单个文件如 @hxsf 所讲的方法
    网页加载无法实时反映加载进度,因为可能直到最后一个文件加载完毕,才会知道数据总量
    RihcardLu
        9
    RihcardLu  
       2018-02-22 17:17:25 +08:00
    技术的角度都说了,说点用户心里有关的。其实进度条的准确度可能不是那么重要,只要给用户那么个东西,『我正在加载,马上就完成了』,用户就会等待更久的时间(相比于什么提示都没有的页面)。
    chairuosen
        10
    chairuosen  
       2018-02-22 17:25:41 +08:00
    单说网页加载:

    <script src='lib1.js'></script>
    <script>setProgressBar(30)</script>
    <script src='lib2.js'></script>
    <script>setProgressBar(60)</script>
    <script src='lib3.js'></script>
    <script>setProgressBar(100)</script>
    edison111cry
        11
    edison111cry  
    OP
       2018-02-22 17:27:00 +08:00
    @chairuosen 我擦,这样倒真是个方法。 不错不错,学习了
    hxsf
        12
    hxsf  
       2018-02-22 17:51:03 +08:00
    @learnshare #8
    1. 链接建立拿到 header -> 更新 total size
    2. 拿到内容 -> 更新 current size
    如:
    1s:189 / 800
    3s: 772 / 1723
    5s: 2300 / 2300 done!


    或者

    当前文件进度:123 / 6123B
    总进度: 26 / 89 个

    因为对于浏览器来说,加载资源可能是多个同时进行的。所以后者不好做。 前者就够了。
    learnshare
        13
    learnshare  
       2018-02-22 18:01:52 +08:00
    @hxsf 已下载量和总量都在变化,进度是要倒退的
    再说,分析关联文件这种事太复杂,除了浏览器本身,其他的都没必要去做
    hxsf
        14
    hxsf  
       2018-02-22 18:13:10 +08:00   ❤️ 1
    @learnshare #13 进度变小,你可以倒退,也可以等待啊。
    有没有必要做,看需求和收益,不是单看复杂不复杂,真有需求,写个 loader 又何妨呢。
    LZ 只是问怎么做。我给了答案。
    做不做,看 LZ 自己喽。
    vuuv
        15
    vuuv  
       2018-02-22 21:45:40 +08:00 via Android
    具体进度主要靠人工提供。

    最简单的就是达到某一阶段提升一个进度。
    例如 0-10-40-70-100

    进度条突然暴增体验不佳,然后有了一些改进来优化体验。
    例如设定 0-10 一般需要 2s,那么进度条缓慢增加,如果你花 1 秒完成了,就突然从 5 跳到 10,如果迟迟没有收到通知,则会卡在 10。

    可惜还是略感不佳,你可以增加额外的判断来动态调整时长。
    例如一开始根据加载速度计算初始时长在 1-3 秒波动。如果 0.5 秒完成了,则加快后续的进度增幅。如果 5 秒才完成,则降低后续的进度增幅。
    如此依次将前一阶段的进度耗时计入下一周期,这样可能看起来时快时慢,但是可以获得相对平滑的进度提示了。

    后面是我的改进思路,实际上我只做到了第二步。
    vuuv
        16
    vuuv  
       2018-02-22 21:51:55 +08:00 via Android
    我上面主要是针对多种耗时不等的情况的。
    任务复杂也可以拆分到多个进度条里提示。然后提示所处阶段。

    至于单一任务,上面提到实时计算就挺好的。额外设置定时动画反而不好。

    进度条主要是告诉用户等待时间,以便客户决定是否“离开一会儿”,避免干等浪费时间。
    vuuv
        17
    vuuv  
       2018-02-22 22:12:05 +08:00 via Android
    特别提醒,我最后构思的持续进度条可能存在部分负优化。

    按照我的思路,如果设定 0-10 耗时 2s 完成动画,如果迟迟没有回应,则会在 2s 后占用下一进度的区间(向 40 进发),不过增幅逐步缓慢下来。在 0-10 完成后,根据之前的延时降低 10-40 的进度增幅。

    如果出现意外导致相应阶段无法完成,这会造成一种它还活着的假象,造成误导。白等浪费时间不说,还会提供错误的进度信息。
    nciyuan
        18
    nciyuan  
       2018-02-22 23:05:17 +08:00 via Android
    原来 Flash 可以,但是现在不行了。
    最基本就是数据大小 /总大小
    一般用户上传这种知道大小的可以直接给条,像是提交表单,或者动态数据,可以处理完一部分加一点
    要是不定的或者别的直接动画
    用条的也尽可能不要卡在 99%,因为如果等待时间很长那么到了 99%用户是不想刷新的
    还有小的数据网速快的话条还没加载好数据都传完了
    Humorce
        19
    Humorce  
       2018-02-22 23:34:38 +08:00 via iPhone
    最牛逼的还是分明一秒处理完,硬要加个 3 秒的进度动画的
    azh7138m
        20
    azh7138m  
       2018-02-22 23:40:56 +08:00 via Android
    @hxsf 老哥,content length 又不是一定会有,gzip 了解一下
    geelaw
        21
    geelaw  
       2018-02-22 23:47:50 +08:00 via iPhone
    @loading 如果你说的是安装补丁,那用的是 **不确定** 进度环,本来就没有进度多少的指示;如果你说的是升级安装系统,那么那个进度环是在反应安装进度的,因此可以出现不动一段时间的情况。
    hxsf
        22
    hxsf  
       2018-02-23 08:21:55 +08:00 via iPhone
    @azh7138m chunk 传输才没有 content length,一般来说流式传输动态内容时才会使用 chunk,普通静态内容都是非 chunk 的
    azh7138m
        23
    azh7138m  
       2018-02-23 08:46:53 +08:00 via Android
    @hxsf

    > When a message does not have a Transfer-Encoding header field, a
    Content-Length header field can provide the anticipated size

    在现代,并不应该假定 content length 是存在的,gzip 很常见
    hxsf
        24
    hxsf  
       2018-02-23 09:47:35 +08:00
    @azh7138m #23 是很常见啊,不过都是针对文本内容的。对于 图片、字体、媒体资源,依然可以知道总大小。

    PS:
    gzip 一般是在 content-encoding
    Transfer-Encoding 一般才是 chunk

    gzip 是可以得知 length 的。不过就需要 server 用 buffer 缓存压缩后的内容,全部压缩完后得到大小在发送(比较伤,所以一般 server 采用 gzip、br 等后就分块传输(可以流式编码了))。

    而对于 js、css 等文本资源,一般文件较小的没有加载进度的需求吧,只有数量较多、总体较大的文件要加载时,才有这个需求,如果服务器不返回 size,则可以采用 已加载数量 /总数量 的方式。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5572 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:35 · PVG 11:35 · LAX 19:35 · JFK 22:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.