1.视频资源请求N次
现象
某视频资源请求死循环,终止不下来。
原因
一段视频,不单纯是视频的内容,它还包含一个视频详情的盒子moov,里面装着:尺寸和每秒的帧数、时长、字幕、版权等等附近信息。而这个moov box可能以任意顺序排列在整个视频的流信息里(二进制文件)。
一般在首个字节的话,那么浏览器只发一次请求即可,如果在末尾,那么就需要发三次请求。如果在中间任意位置,那浏览器就要尝试发N次请求去拿取。
那为啥要寻找moov
因为,程序要定位到视频的开始位置,需要找到一份钥匙,进而打开宝藏。
如果是本地播放由于你已经拥有整个视频文件,不会有啥问题;但如果浏览器在线观看,也就是流传输(二进制字节一个个码齐) HTML5 视频时,就有问题了。
上图,看真相。
首次: 尝试从第一个字节寻找
没找到,通过 Range 头读取文件末尾数据。发起二次请求。
大部分视频资源,基本都找到了。于是发起第三次请求拿取视频流。
如果是个奇葩的视频资源,不知道是谁合成了它,还是没找到,那就要开始了多次寻找之路。
解决
借助视频处理工具把 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 })
原因
所以:
其它的耗时,包括TTFB,这种等待服务端计算处理的时间,是不在progress里的。loading 在await之后,也就是在等待服务端给到反馈后才终止的。
3. img的魔性之处
现象
图片上传后,展示到img标签里的过程中,会刷新整个页面。 打开网络请求面板,发现又重新请求了当前页。不科学,哪里触发的呢?
每个网络请求都有一个启动器,标识出了,发起人一步步的调用堆栈,最后看到的是image对象。那么为什么呢,img有这个能力?
ps:这里出现CORS 跨域,是因为项目被iframe到别的系统里,所以请求父页面出现跨域问题。
原因
当img标签的src为空字符时候,浏览器会给img一个缺省值,就是当前页面地址。所以会自动请求当前页面,试图请求回来填充到图片标签里。
解决
如果是vue项目里,可以给img标签一个if,当图片上传完成回显时候,再展示img标签。如果是原生,可以上传完成后再创建image对象。给src赋值。
var img = new Image();
img.src = "上传成功后,服务端给的图片服务器地址";
其实火狐在十四年之前,已经修复了这个问题,如今主流的 Safari 和 谷歌 还是有这个问题。