前端网络、JavaScript优化以及开发小技巧
一、网络优化
YSlow有23条规则,中文可以参考这里。这几十条规则最主要是在做消除或减少不必要的网络延迟,将需要传输的数据压缩至最少。
1)合并压缩CSS、JavaScript、图片,静态资源CDN缓存
通过构建工具Gulp,可以在开发的时候就将合并压缩的事情一起做掉。
之所以要做合并压缩是因为:HTTP 1.x不允许一个连接上的多个响应数据交错到达(多路复用),因而一个响应必须完全返回后,下一个响应才会开始传输。
也就是说即使客户端同时发送了两个请求,而且CSS资源先准备就绪,服务器也会先发送HTML响应,然后再交付CSS。
使用CDN是为了让用户访问的时候能用最近的资源,减少来回传输时间。
HTTP2.0改进了HTTP1.x很多方面。
2)CSS放顶部,JavaScript放底部
CSS可以并行下载,而JavaScript加载之后会造成阻塞。
但凡事还是会有例外,如果把行内脚本放在样式表之后,会明显地延迟资源的下载(结果是样式表下载完成并且行内脚本执行完毕时,后续资源才能开始下载)。
这是因为行内脚本可能含有依赖于样式表中样式的代码,比如document.getElementsByClassName()。
<head>
<link rel="stylesheet" href="css/all-normal.css" type="text/css" />
</head>
<body>
<div id="content"></div>
<script>
var content = '';
for(i=1; i<1000000; i++)
content += '写入页面';
document.getElementById('content').innerHTML = content;
</script>
<img src="data:images/ui.png" />
</body>
下面通过Chrome的工具查看下:
3)优化DNS解析,减少重定向
在做一个“女神评选活动”的时候,需要在微信中访问能够获取用户的openid,微信获取用户基本信息是需要经过几个步骤的:
先获取code,再通过code获取openid,最后再跳转访问静态页面。
由于公司将业务分成了多个小组,所以短短的三步其实需要三个小组配合,需要重定向多个域名。
下图是未优化前的瀑布图,但不是最坏情况,有时候访问到静态页面需要经过10多秒,完全不能接受,下图中会跳转4个域名:
后面不跳index那个域名,直接跳转到微信操作域名,减少一个域名的跳转,各小组代码再做优化,但效果还是不理想,仅仅快了几秒。
最后发现其实是在与微信的服务器做交互的时候,DNS解析花了太多时间!不得已,在服务器的host中添加一条记录,直接通过IP指向。
下图是最终优化结果,虽然达不到秒开,但至少可以接受了:
二、JavaScript优化
1)图片预加载
在做一个“秋名山活动”的时候,使用了图片预加载。这个活动中有120多张图片。
流程很简单,就是答题,最后给评论结果,再分享出去。
如果一下子加载那么多图片,一定是愚蠢的想法,最后决定,在页面载入的时候先加载一些通用图片。
在答题的时候当前页面,预先加载后面页面中的图片,防止访问页面的时候直接不展示图片,图片也做了适当的合并。
将网站地址放在gtmetrix.com测试,下面是最终的瀑布图,可以发现图片都在其他静态资源的后面,这样能尽早的展现页面给用户:
优化还远远没有结束,在Chrome中分别模拟了good 2G、good 3G以及4G后,有结果的情况并不理想。
good 2G:
good 3G:
4G:
还有很大的优化空间可以做,关于这个预加载的原理,可以参考《图片预加载与懒加载》
2)减少分支
在写业务逻辑的时候,经常会用到if else,switch之类的逻辑判断,如果每次都做这么多判断,很容易影响性能。
所以可以通过多种方式来避免过多的判断。
1. 惰性模式
这是在看《JavaScript设计模式》的时候看到的。
减少每次代码执行时的重复性分支判断,通过对对象重定义来屏蔽原对象中的分支判断。
惰性模式分为两种:第一种文件加载后立即执行对象方法来重定义,第二种是当第一次使用方法对象时来重定义。
公司有个页面要提供给第三方APP,但是最终发现第三方APP不能使用localStorage缓存,最终只得做兼容的方式。
但为了避免每次引用方法的时候都做判断,就使用加载后立即重定义:
var getFn = function() {
if (sore.enabled)
return sore.get;
return cookie.get;
}();
var setFn = function() {
if (sore.enabled)
return sore.set;
return cookie.set;
}();
2. 建立映射关系
页面中经常需要弹出框提示,后面就自己做了一个,但弹出框会有很多款式。
如果用简单工厂模式创建的话,免不了switch分支判断,后面就直接用赋不同的key,还能缓存起来,只初始化一次。
/**
* 弹出框单例模式
*/
var factories = {};
var DialogFactory = function(type, options) {
if (factories[type])
return factories[type];
return factories[type] = new iDialog(options);
};
/**
* 提示框
*/
var Alert = function(content, options) {
var d = DialogFactory('alert', options);
//其他逻辑省略
return d;
};
/**
* 确认框
*/
var Confirm = function(content, options) {
var d = DialogFactory('confirm', options);
//其他逻辑省略
return d;
};
3)第三方代码异步加载
第三方代码,例如百度统计、微信SDK等,这些完全可以在将业务资源加载完后再添加。
/**
* 百度统计设置
*/
util.baidu = function(key) {
global._hmt = global._hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?" + key;
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
};
4)cookie与localStorage缓存
有了缓存后,就能减少与服务器的通信,在本地操作。
公司有个查违章的业务,在本地添加好车辆后,再次进入页面的时候就需要能直接选择事先添加好的车辆。
最理想的方式就是添加好后,就在本地缓存起来,下次进入直接调取缓存。
我会优先使用localStorage,下面的表格就是对比:
cookie |
localStorage | |
数据生命周期 |
可设置失效时间 | 除非被清除,否则永久保存 |
数据大 |
大约4KB | 大约5M |
与服务器通信 |
每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 不参与和服务器的通信 |
本地存储,之前的历史大概如下图所示:
localStorage在浏览器兼容方面,IE8居然也支持了。
5)事件委托
使用事件委托技术能让你避免对特定的每个节点添加事件监听器。
事件监听器是被添加到它们的父元素上,通过事件冒泡,触发执行。
在开发的时候,经常会出现动态添加元素的情况。
如果每次都重新绑定一次事件,那会有很多多余操作,而绑定在此元素的父级,就只需绑定一次即可。
document.getElementById('ul').onclick = function(e) {
var e = e || window.event,
tar = e.target || e.srcElement;
if (tar.nodeName.toLowerCase() == 'li') {
tar.style.background = 'black';
}
}
6)节流与去抖动
节流(throttle):预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
例如mousemove 事件、window对象的resize和scroll事件。
去抖动(debounce):当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。
例如文本输入keydown 事件,keyup 事件,做autocomplete等。
节流与去抖动最大的不同的地方就是在计算最后执行时间的方式上。著名的开源工具库underscore中有内置了两个方法。
在做公司内部的一个系统的时候,需要方希望在左右滚动表格的时候,能将第一列固定在最左边,方便查看。
为了让操作能更流畅,我再这里用了节流,有些浏览器会出现卡顿,就得需要增加周期时间。
三、小技巧
1)在手机中打印变量
在移动页面的时候经常需要调试字段,又不能用console.log,每次alert的话,碰到对象就看不到内容了。
只能自己写个小方法来打印出来,JSON.stringify,通过这个方法能够方便的实现功能。
var print = function(obj, space) {
space = space || 4;
var html = JSON.stringify(obj, null, space);
html = html.replace(/\n/g, '<br>').replace(/\s/g, ' ');
var pre = document.createElement('pre');
var div = document.createElement('code');
pre.style.cssText = 'border:1px solid #000;padding:10px;background:#FFF;margin-bottom:20px;';
div.innerHTML = html;
pre.appendChild(div);
var body = document.querySelector('body');
body.insertBefore(pre, body.children[0]);
}; print({a:1, b:'demo', c:{text:'content'}});
2)chrome插件JSON-handle
服务器返回的很多都是JSON格式的数据,通常写好后给你个接口,顺便给你几个demo参数。
在浏览器中打开后,就是一串字符串,但要给人看的话,就得格式化一下了,这个插件就是用来让人看的。
前端网络、JavaScript优化以及开发小技巧的更多相关文章
- 前端日常工作中常用开发小技巧 ---JavaScript
1.格式化金钱值 const ThousandNum = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "," ...
- flex开发小技巧集锦
关于flex开发网上有非常多的相关信息介绍,因此我们要想学习关于flex开发的知识信息技能是一件非常简单和方便的事情.而针对于flex开发小编要告诉大家的是一些flex开发小技巧.利用这些小技巧能够有 ...
- TP开发小技巧
TP开发小技巧原文地址http://wp.chenyuanzhao.com/wp/2016/07/23/tp%E5%BC%80%E5%8F%91%E5%B0%8F%E6%8A%80%E5%B7%A7/ ...
- 移动Web开发小技巧
移动Web开发小技巧 添加到主屏后的标题(IOS) name="apple-mobile-web-app-title" content="标题"> 启用 ...
- Windows统一平台: 开发小技巧
Windows统一平台: 开发小技巧 技巧一: 在手机端拓展你应用的显示区域.(WP8.1中也适用) 对于Windows Phone系统的手机, 手机屏幕最上方为系统状态栏(System Tray), ...
- BizTalk开发小技巧
BizTalk开发小技巧 随笔分类 - Biztalk Biztalk 使用BizTalk实现RosettaNet B2B So Easy 摘要: 使用BizTalk实现RosettaNet B2B ...
- Java开发小技巧(三):Maven多工程依赖项目
前言 本篇文章基于Java开发小技巧(二):自定义Maven依赖中创建的父工程project-monitor实现,运用我们自定义的依赖包进行多工程依赖项目的开发. 下面以多可执行Jar包项目的开发为例 ...
- iOS开发小技巧 - UILabel添加中划线
iOS开发小技巧 遇到的问题: 给Label添加中划线,然后并没有效果 NSString *str = [NSString stringWithFormat:@"合计金额 ¥%.2f&quo ...
- PHP开发小技巧②—实现二维数组根据key进行排序
在PHP中内置了很多对数组进行处理的函数,有很多时候我们直接使用其内置函数就能达到我们的需求,得到我们所想要的结果:但是,有的时候我们却不能通过使用内置函数实现我们的要求,这就需要我们自己去编写算法来 ...
随机推荐
- Travis CI用来持续集成你的项目
这里持续集成基于GitHub搭建的博客为项目 工具: zqz@ubuntu:~$ node --version v4.2.6 zqz@ubuntu:~$ git --version git versi ...
- J a v a 的“多重继承”
接口只是比抽象类“更纯”的一种形式.它的用途并不止那些.由于接口根本没有具体的实施细节——也就是说,没有与存储空间与“接口”关联在一起——所以没有任何办法可以防止多个接口合并到一起.这一点是至关重要的 ...
- VS项目中使用Nuget还原包后编译生产还一直报错?
Nuget官网下载Nuget项目包的命令地址:https://www.nuget.org/packages 今天就遇到一个比较奇葩的问题,折腾了很久终于搞定了: 问题是这样的:我的解决方案原本是好好的 ...
- WPF 捕获键盘输入事件
最近修改的一个需求要求捕获键盘输入的 Text,包括各种标点符号. 最开始想到的是 PreviewKeyDown 或者 PreviewKeyUp 这样的键盘事件. 但是这两个事件的对象 KeyEven ...
- ADO.NET一小记-select top 参数问题
异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...
- 微服务与Docker介绍
什么是微服务 微服务应用的一个最大的优点是,它们往往比传统的应用程序更有效地利用计算资源.这是因为它们通过扩展组件来处理功能瓶颈问题.这样一来,开发人员只需要为额外的组件部署计算资源,而不需要部署一个 ...
- CommandPattern
/** * 命令模式 * @author TMAC-J * 将调用者和接受者分离 * 可以将一组命令组合在一起,适合很多命令的时候 */ public class CommandPattern { i ...
- 【干货分享】流程DEMO-出差申请单
流程名: 出差申请 业务描述: 员工出差前发起流程申请,流程发起时,会检查预算,如果预算不够,将不允许发起费用申请,如果预算够用,将发起流程,同时占用相应金额的预算,但撤销流程会释放相应金额的预算. ...
- Android 死锁和重入锁
死锁的定义: 1.一般的死锁 一般的死锁是指多个线程的执行必须同时拥有多个资源,由于不同的线程需要的资源被不同的线程占用,最终导致僵持的状态,这就是一般死锁的定义. package com.cxt.t ...
- Linux下高cpu解决方案
昨天搞定了一个十万火急的issue,客户抱怨产品升级后系统会变慢和CPU使用率相当高,客户脾气很大,声称不尽快解决这个问题就退货,弄得我们 R&D压力很大,解决这个issue的任务分给了我,客 ...