优化首屏加载体验
发布于 8 年前 作者 wq123456 7929 次浏览 来自 分享

最近被公司派去帮内容营销的同事搞活动,慢慢的成了切图的熟练工,然而面对重要活动时候还是为了追求极致加载速度而去深入折腾一番。下面就让我来分享下自己的经验。 首先简单说明下浏览器解析顺序: -> HTML 解析完毕 -> 外部脚本和样式表加载完毕 -> 脚本在文档内解析并执行 -> HTML DOM 完全构造 -> 图片和外部内容加载 -> 网页完成加载 那么我们可以针对这些步骤做哪些工作呢?下面让我借例子道来。 未优化.png 这张图是未优化前我用chrome记录下的,可以看到DOMContentLoaded的时间是231ms,而完全加载完时间是24.76s,当然这跟我去掉缓存也有一定影响,这样说来首页加载的速度还勉强可以,但是完全加载的时间却很难让人忍受。接下来我们看看google的pagespeed insights怎么说 未优化2.png未优化3.png未优化4.png 总结一下就是图片需要压缩,首屏用不到的js该去去掉,css中先把有用的样式拿出来嵌入到页面上。 图片压缩的问题我们可以用gulp 插件imgmin

var minimgpath = yourproj path;
gulp.task('imgmin', function() {
   return gulp.src(minimgpath + '/**')
       	 	.pipe(imagemin({
           		 progressive: true,
            	svgoPlugins: [{
                	removeViewBox: false
            	}],
           	 use: [pngquant()]
        	}))
        	.pipe(gulp.dest(minimgpath + '/'));
});
		

goolge建议的是无损压缩,然而你可以根据需要设置,这边默认设置可以压缩25%左右。做好压缩后接下来就是去掉相关的脚本文件和css文件 到现在我们可以继续说上面的浏览器解析的事了。方案是针对首屏dom解析完毕的事件做监听,在这个事件完成后说明首屏页面加载完了,然后再去加载其他的资源。 其中跟dom加载相关的事件有两个document的DOMContentLoaded 和 window 的 load 事件,两者的区别是 前一个在dom加载完后触发,不用管界面的图片什么的,而后者则是需要全部界面资源加载完后才会触发。为了更加稳妥的考虑我们参考jquery的$(document).ready();把两者共同用上

function completed() {
       document.removeEventListener( "DOMContentLoaded", completed );
        window.removeEventListener( "load", completed );
        //do loading
 }
document.addEventListener("DOMContentLoaded", completed );
window.addEventListener("load", completed );
	

这边doloading 自然就是加载 脚本。我们利用动态创建脚本以及它的onload事件来加载js及控制加载的前后顺序

function loadScript(src,callback) {
       var javascript = document.createElement('script');
       javascript.async = true;
       javascript.type = 'text/javascript';
       var head = document.getElementsByTagName('head')[0];
       head.appendChild(javascript);
       if(callback) {
          if(navigator.appName.toLowerCase().indexOf('netscape') === -1) {
            if(javascript.onreadyState === 'complete') {
                    callback();
			}
         } else {
                javascript.onload = function() {
                    callback();
                }
            } 
       }
      
       javascript.src = src;
}
loadScript('load a script',loadB );
	

这样我们组合一下两段代码


function loadScript(src,callback) {
        var javascript = document.createElement('script');
        javascript.async = true;
        javascript.type = 'text/javascript';
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(javascript);
        if(callback) {
           if(navigator.appName.toLowerCase().indexOf('netscape') === -1) {
            if(javascript.onreadyState === 'complete') {
                    callback();
            }
         } else {
                javascript.onload = function() {
                    callback();
                }
            } 
        }
        
        javascript.src = src;
    }
function addScriptQueue() {
        loadScript('//res.wx.qq.com/open/js/jweixin-1.0.0.js');
        loadScript('//cdn.yoho.cn/yohodesiner/1.0.2/js/lib/swiper-3.3.1.jquery.min.js');
        loadScript('{{jspath}}loading_yohood.js?v=1');
        loadScript('{{jspath}}yohood/index.wechat.js?v=1');
}
function completed() {
        document.removeEventListener( "DOMContentLoaded", completed );
        window.removeEventListener( "load", completed );
        loadScript('http://cdn.yoho.cn/yohodesiner/1.0.2/js/lib/jquery-1.10.1.min.js',addScriptQueue);
    }
 document.addEventListener("DOMContentLoaded", completed );
 window.addEventListener("load", completed );
	

就可以实现我们想要的等首屏dom加载完后按顺序动态加载需要的脚本。至于css 的处理方式可以看看 pagespeed insights给的 css优化.png 考虑到css本身文件较小我没有去对他也进行后续加载。下面是优化后的结果: 优化后.png 优化后2.png 还是变快了的。 这边是这次活动 yohood的链接,有兴趣可以点点。

4 回复

换个思路,只要边加载边输出体验不会差,进度条都不必须

mark

来自酷炫的 CNodeMD

mark,正为这事心烦,感谢分享 From Noder

回到顶部