最近遇到一上神,称他为上神,是基于他的识人能力、对行业痛点的思考以及解决问题的能力,这些都足以让他成为我的师傅,其实我跟他也就简单的聊十几分钟,他就可以找到我的问题所在,帮我认识自己,这是自我认知的有效途径之一。
我的问题一:不爱思考
其实在两年前,我就知道我有这个毛病,没想到我认为的小毛病,现在却成为限制我发展的瓶颈。当上神指出我的问题的时候,我还“狡辩”说,太过于专注业务的开发,而没去做这些思路。上神指责我,我思维就有问题,在做的时候就应该思考,而不是只做不思考。
培养思维
想想也是只有不断的思考,抛出问题,虽然当时没有搞懂,没有满意的答案,但是脑海里有这个问题库。在后面的读书、查资料、做业务、沟通交流的时候,就能碰上每个问题,就消灭掉一个问题。与此同时,随着问题的抛出,问题的延伸,自然而然对这个领域有了一定的思想沉淀,不管是深度和广度上都有了一定的扩展。
修炼内功
我也不应该去逃避现实,面对自身的短板,去调整自己才是上上策,才能迎接更好的自己。只有达到一定的层次,夯实基础才有资格成为上神的徒弟。毕竟我算不上天赋异禀,没有深厚的内功。上神又有什么理由要收我为徒。
如何监听当前页面上的所有img图片的加载情况
言归正传,回到今天的主题:如何监听当前页面上的所有img图片的加载情况,每张图片什么时候开始加载,什么时候加载成功,或者加载失败。将图片的加载情况汇总,然后上报到服务器。
最初思考
最近在做vue项目,找了一个正在开发业务练手,我选择在mounted生命周期里去处理。
最初的思路是:先获取到当前页面所有的img图片,遍历所有图片,遍历到每张图片开始记录加载开始时间,同时监听图片的加载成功、失败、缓存的时间以及状态。计数统计处理的图片,当统计完成,向服务上报。
imgLoadCtrl();
function imgLoadCtrl() {
let imgs = document.querySelectorAll('img');
let arr = [] // 图片的加载情况
let count = 0 // 图片加载完成张数(包含加载失败图片 和缓存图片)
let progress = 0 // 图片加载进度
// console.time()
Array.from(imgs).forEach((item, index) => {
arr[index] = {
startTime: +new Date()
};
// 获取新加载的图片
item.onload = (e) => {
addLoadMessage(arr, item, index, 'loadFinished')
}
// 获取加载失败的图片
item.onerror = (e) => {
addLoadMessage(arr, item, index, 'loadError')
}
// 获取缓存的图片
item.oncomplete = (e) => {
addLoadMessage(arr, item, index, 'loadCache')
}
})
// 图片加载情况数据整理
function addLoadMessage(arr, item, index, load) {
arr[`${index}`].endTime = +new Date()
arr[`${index}`].src = item.getAttribute('src')
arr[`${index}`].index = index
arr[`${index}`].loadTime = (arr[`${index}`].endTime - arr[`${index}`].startTime) + 'ms'
arr[`${index}`].load = load
// console.log(arr)
sumAdd()
}
// 计数函数
function sumAdd() {
count++
// 预留图片加载进度
progress = Math.ceil(count/7*100);
(progress>=100) ? 100 : progress
// console.log(progress)
// 图片加载完成 向服务器上报
if (count == arr.length) {
message()
}
}
// 向服务器发送当前页面的图片加载情况
function message () {
let imgObject = {
url: location.href,
count: count,
loadArr: arr
}
// 请求接口
console.log(imgObject)
}
// console.timeEnd()
}
向服务器回报:
- (1)当前页面地址;
- (2)图片张数;
- (3)每张图片的加载情况;
{url: "https://m2.qschou.com/v8/glowwormPlan/guide.html?islogin=1&islogin=1", count: 4, loadArr: Array(4)}
count: 4
loadArr: Array(4)
0: {startTime: 1545284954692, endTime: 1545284954760, src: "https://static2.qschou.com/img/v8/glowwormPlan/guide/assets/g-head-bg.png", index: 0, loadTime: "68ms", …}
1: {startTime: 1545284954692, endTime: 1545284954781, src: "https://static2.qschou.com/img/v8/glowwormPlan/guide/assets/g-icon1.png", index: 1, loadTime: "89ms", …}
2: {startTime: 1545284954692, endTime: 1545284954784, src: "https://static2.qschou.com/img/v8/glowwormPlan/guide/assets/g-icon2.png", index: 2, loadTime: "92ms", …}
3: {startTime: 1545284954692, endTime: 1545284954795, src: "https://static2.qschou.com/img/v8/glowwormPlan/guide/assets/g-icon3.png", index: 3, loadTime: "103ms", …}
length: 4
__proto__: Array(0)
url: "https://m2.qschou.com/v8/glowwormPlan/guide.html?islogin=1&islogin=1"
__proto__: Object
发现新问题
看上去这样处理,好像可以得到,一个当前页面的所有图片的加载情况。实际上并没有拿到图片真正开始加载的时间。而且Date对象的方法都只能精确到毫秒级别(一秒的千分之一),想到得到精确的时间差别Date对象也是无能为力,无法知道图片加载的时间进度。
遇上performance
在ES5中有一个“高精度时间戳API”,部署在 performance
对象。它的精度可以达到微秒(1毫秒的千分之一)。
performance.getEntries() 带给我们的惊喜
浏览器在获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个http请求。performance.getEntries方法以数组形式,返回这些请求的时间统计信息,有多少个请求,返回数组就会多少个成员。该方法只能在浏览器中使用。window.performance.getEntries()
,返回一个高精度的时间戳对象,每个属性的单位是微秒(microsecond), 即百万分之一秒。
在 萤火虫计划攻略 页面上测试performance.getEntries()
。
performance.getEntries()
可以获取到所有资源的请求信息。我们需要过滤掉无用的资源信息,只保留图片。在过滤图片的
let arr = window.performance.getEntries()
let newArr = []
arr.forEach((item) => {
if (item.initiatorType == 'img' && item.name.indexOf('https://hm.baidu.com') == -1 && item.name.indexOf('https://recevapi.qschou.com/dtas') == -1) {
newArr.push(item)
}
})
console.log(newArr)
拿到所有图片的请求时间统计信息。取performance.getEntries()[0]
第一张图片的统计信息:
connectEnd: 0 // 返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的时持久连接,则返回值等同与fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。
connectStart: 0 // 返回http请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回等同于fetchStart属性的值
decodedBodySize: 0
domainLookupEnd: 0 //返回域名查询结束时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。
domainLookupStart: 0// 返回域名查询开始时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回等同与fetch属性的值。
duration: 0
encodedBodySize: 0
entryType: "resource"
fetchStart: 774.6000000042841//返回浏览器准备使用http请求读取文档时的Unix毫秒时间戳。该事件在网页查询本地缓存之前发生。
initiatorType: "img"
name: "https://static2.qschou.com/img/v8/glowwormPlan/guide/assets/g-head-bg.png"
nextHopProtocol: "http/1.1"
redirectEnd: 0 // 返回最后一个http跳转结束时的 unix毫秒时间戳。如果没有跳转,或者不是通一个域名内部的跳转,则返回值为0
redirectStart: 0 // 返回最后一个http跳转开始时的 unix毫秒时间戳。如果没有跳转,或者不是通一个域名内部的跳转,则返回值为0
requestStart: 0 // 返回浏览器向服务器发出http请求时(或从本地缓存读取)最后一个字节时的毫秒时间戳。
responseEnd: 774.6000000042841 // 返回浏览器从服务器收到最后一个字节时的毫秒时间戳
responseStart: 0
secureConnectionStart: 0//返回浏览器与服务器开始安全连接的握手时的毫秒时间戳。如果当前网页不需要安全连接,则返回0
serverTiming: []
startTime: 774.6000000042841
transferSize: 0
workerStart: 0
其中重要的是 duration、fetchStart、responseEnd、startTime,我们就知道图片的开始加载时间,结束加载时间,以及加载持续时间。
duration: 24.900000003981404 //加载持续时间
fetchStart: 570.2999999921303 //返回浏览器准备使用HTTP请求读取文档时的毫秒时间戳
responseEnd: 595.1999999961117 //返回浏览器从服务器收到最后一个字节时的毫秒时间戳
startTime: 570.2999999921303//开始时间加载时间