开发问题记录

136 阅读3分钟

1.视频资源请求N次

现象

某视频资源请求死循环,终止不下来。

原因

一段视频,不单纯是视频的内容,它还包含一个视频详情的盒子moov,里面装着:尺寸和每秒的帧数、时长、字幕、版权等等附近信息。而这个moov box可能以任意顺序排列在整个视频的流信息里(二进制文件)。

一般在首个字节的话,那么浏览器只发一次请求即可,如果在末尾,那么就需要发三次请求。如果在中间任意位置,那浏览器就要尝试发N次请求去拿取。

那为啥要寻找moov

因为,程序要定位到视频的开始位置,需要找到一份钥匙,进而打开宝藏。

如果是本地播放由于你已经拥有整个视频文件,不会有啥问题;但如果浏览器在线观看,也就是流传输(二进制字节一个个码齐) HTML5 视频时,就有问题了。

上图,看真相。

首次: 尝试从第一个字节寻找

2022-10-17.150638.png

没找到,通过 Range 头读取文件末尾数据。发起二次请求。

image.png

大部分视频资源,基本都找到了。于是发起第三次请求拿取视频流。

image.png 如果是个奇葩的视频资源,不知道是谁合成了它,还是没找到,那就要开始了多次寻找之路。

image.png

解决

借助视频处理工具把 Moov box 提到视频首个字节位置即可。

参考

张鑫旭 从天猫某活动视频不必要的3次请求说起一文中有详细的阐述。


2.xhr的 progress 进度偏差问题

progress 和 loading的步调不一致

现象

利用xhr对象自带的进度对象做的progress。同时添加了loading效果,但是发现,图片上传完毕后,loading 要滞后进度4s多才停下来。也就是进度先达到100%了,圈圈没停。

一份伪代码,简单表述下过程:

   async function upload() {
      var progressBar = document.getElementById("p");

      var xhr = new XMLHttpRequest();

      xhr.open("GET", "url:xxx");
      //开loading
      loading = true
      //开进度
      xhr.onprogress = function (event) {
        progressBar.max = event.total;
        progressBar.value = event.loaded;
      };
      xhr.onloadend = function (event) {
        progressBar.value = event.loaded;
      };
      xhr.send();
    }

    //关闭loading
    await upload(()={ loading = false })

原因

image.png

所以: 其它的耗时,包括TTFB,这种等待服务端计算处理的时间,是不在progress里的。loading 在await之后,也就是在等待服务端给到反馈后才终止的。 image.png


3. img的魔性之处

现象

图片上传后,展示到img标签里的过程中,会刷新整个页面。 打开网络请求面板,发现又重新请求了当前页。不科学,哪里触发的呢?

每个网络请求都有一个启动器,标识出了,发起人一步步的调用堆栈,最后看到的是image对象。那么为什么呢,img有这个能力? image.png

ps:这里出现CORS 跨域,是因为项目被iframe到别的系统里,所以请求父页面出现跨域问题。

原因

当img标签的src为空字符时候,浏览器会给img一个缺省值,就是当前页面地址。所以会自动请求当前页面,试图请求回来填充到图片标签里。

解决

如果是vue项目里,可以给img标签一个if,当图片上传完成回显时候,再展示img标签。如果是原生,可以上传完成后再创建image对象。给src赋值。

var img = new Image();

img.src = "上传成功后,服务端给的图片服务器地址";

其实火狐在十四年之前,已经修复了这个问题,如今主流的 Safari 和 谷歌 还是有这个问题。