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="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, '&nbsp');
 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参数。

在浏览器中打开后,就是一串字符串,但要给人看的话,就得格式化一下了,这个插件就是用来让人看的。

时间: 2017-01-31

JS对img标签进行优化使用onerror显示默认图像

对于网站图像的不显示有很多原因,网络问题,文件本身问题,文件URL问题等,而当图像加载失败时会触发onerror这个事件,我们利用这点,可以有效的避免图像加载失败的尴尬! js代码 复制代码 代码如下: //图像加载出错时的处理 function errorImg(img) { img.src = "http://static.xuexiba.com/uploadfile//UserInfo/Avatar/201403/1303992393385832875324.jpg"; img.

js中if语句的几种优化代码写法

尽管我还没使用它去做一些尝试性的测试,但从这里可以看到它的确对js作了美化的工作.也许有人认为if语句就那么简单,能优化到什么程度?但是看看以下的几种方式,你也许会改变看法. 一.使用常见的三元操作符 复制代码 代码如下: if (foo) bar(); else baz(); ==> foo?bar():baz(); if (!foo) bar(); else baz(); ==> foo?baz():bar(); if (foo) return bar(); else return baz

JavaScript也谈内存优化

相对C/C++ 而言,我们所用的JavaScript 在内存这一方面的处理已经让我们在开发中更注重业务逻辑的编写.但是随着业务的不断复杂化,单页面应用.移动HTML5 应用和Node.js 程序等等的发展,JavaScript 中的内存问题所导致的卡顿.内存溢出等现象也变得不再陌生. 这篇文章将从JavaScript 的语言层面进行内存的使用和优化的探讨.从大家熟悉或略有耳闻的方面,到大家大多数时候不会注意到的地方,我们一一进行剖析. 1. 语言层面的内存管理 1.1 作用域 作用域(scope

Extjs优化(二)Form表单提交通用实现

复制代码 代码如下: /** * 提交表单 */ function $postForm(a) { if (a.formPanel.getForm().isValid()) { var b = a.scope ? a.scope: this; a.formPanel.getForm().submit({ scope: b, url: a.url, method: "post", params: a.params, waitMsg: "正在提交数据...", succe

js 优化次数过多的循环 考虑到性能问题

假设要生成一千万个随机数,常规的做法如下: 复制代码 代码如下: var numbers = []; for (var i = 0; i < 10000000; i++) { numbers.push(Math.random()); } 然而,在IE下执行这段代码时,却弹出了一个窗口提示用户是否停止这段脚本.出现这种情况,首先想到的是优化循环体.但明显地,循环体很简单,没什么优化的余地.即使把循环体清空,提示仍然存在.于是,我得出了一个结论:在IE下,一旦循环次数超过了某个特定值,就会弹出停止脚

Uglifyjs(JS代码优化工具)入门 安装使用

你也可以尝试一下在线版的Uglifyjs: http://sweet.fengyin.name/ 需要先安装node,进入命令行,查看node,npm是否正确安装. 接下来安装UglifyJS,命令如:npm install uglify-js -g 最后别忘了把node和npm添加到环境变量中,我的分别是 C:\Program Files (x86)\nodejs\; C:\Users\taozhou\AppData\Roaming\npm; 现在就可以使用uglifyjs就行压缩了,如 ug

nodejs的10个性能优化技巧

下面是我们使用Node.js时遵循的10个性能规则: 1. 避免使用同步代码 在设计上,Node.js是单线程的.为了能让一个单线程处理许多并发的请求,你可以永远不要让线程等待阻塞,同步或长时间运行的操作.Node.js的一个显著特征是:它从上到下的设计和实现都是为了实现异步.这让它非常适合用于事件型程序. 不幸的是,还是有可能会发生同步/阻塞的调用.例如,许多文件系统操作同时拥有同步和异步的版本,比如writeFile和writeFileSync.即使你用代码来控制同步方法,但还是有可能不注意

javascript教程:关于if简写语句优化的方法

UglifyJS是一个对javascript进行压缩和美化的工具,在它的文档说明中,我看到了几种关于if语句优化的方法.尽管我还没使用它去做一些尝试性的测试,但从这里可以看到它的确对js作了美化的工作.也许有人认为if语句就那么简单,能优化到什么程度?但是看看以下的几种方式,你也许会改变看法. 一.使用常见的三元操作符 if (foo) bar(); else baz(); ==> foo?bar():baz();if (!foo) bar(); else baz(); ==> foo?baz

js性能优化 如何更快速加载你的JavaScript页面

确保代码尽量简洁 不要什么都依赖JavaScript.不要编写重复性的脚本.要把JavaScript当作糖果工具,只是起到美化作用.别给你的网站添加大量的JavaScript代码.只有必要的时候用一下.只有确实能改善用户体验的时候用一下. 尽量减少DOM访问 使用JavaScript访问DOM元素很容易,代码更容易阅读,但是速度很慢.下面介绍几个要点:限制使用JavaScript来修饰网页布局,把针对访问元素的引用缓存起来.有时,当你的网站依赖大量的DOM改动时,就应该考虑限制你的标记.这是改用

Android布局性能优化之按需加载View

有时应用程序中会有一些很少用到的复杂布局.在需要它们的时候再加载可以降低内存的消耗,同时也可以加快界面的渲染速度. 定义ViewStub ViewStub是一个轻量级的View,它没有高宽,也不会绘制任何东西.所以它的加载与卸载的成本很低.每个ViewStub都可以使用android:layout属性指定要加载的布局. 下面这个ViewStub用于一个半透明的ProgressBar的加载.它只有在新工作开始时才会显示. <ViewStub android:id="@+id/stub_imp

优化Jquery,提升网页加载速度

总是从ID选择器开始继承 在class前使用tag 将jquery对象缓存起来 掌握强大的链式操作 使用子查询 对直接的DOM操作进行限制 冒泡 消除无效查询 推迟到 $(window).load 压缩js 全面掌握jquery库 1. 总是从ID选择器开始继承 在jquery中最快的选择器是ID选择器. 因为它直接来自于Javascript的getElementById()方法. 复制代码 代码如下: <div id="content"><form method=&

无阻塞加载js,防止因js加载不了影响页面显示的问题

浏览器加载静态资源和js的方式都是线性加载,所以一般情况可以将js放到</body>前,防止UI线程的阻塞. 而某些时候我们既希望js在整个网页的头部就加载,又担心js阻塞导致网站加载缓慢,就可以用到无阻塞加载js技术. Dynamic Script Elements 动态脚本元素 DOM允许我们使用Javascript动态创建HTML的几乎所有文档内容,一个新的<script>元素可以非常容易的通过标准DOM创建: var script = document.createElem

JS实现加载时锁定HTML页面元素的方法

本文实例讲述了JS实现加载时锁定HTML页面元素的方法.分享给大家供大家参考,具体如下: 在html加载时js锁定页面内所有input,textarea,select  具体js如下 index.js for(z=0;z<document.getElementsByTagName('input').length;z++) { document.getElementsByTagName('input')[z].setAttribute('disabled','disabled') } for(zz

利用JS实现简单的瀑布流加载图片效果

今天学习了一个瀑布流加载效果,很多网站都有瀑布流效果,瀑布流就是很多产品显示在网页上,宽相同,高度不同,表现为多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部. 原理是: 1.设定一行中的列数: 2.取第一行中每一个div的高度并把每一个高度放进一个数组中: 3.算出数组中最小高度的index值: 4.把第二行的第一个div放到最小高度的div的下方并把重新算出的高度值放进数组中,重新计算最小高度的index值: 5.以此类推实现多栏布局的瀑布流效果: 6.如果最后一

js+HTML5 canvas 实现简单的加载条(进度条)功能示例

本文实例讲述了js+HTML5 canvas 实现简单的加载条(进度条)功能.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>www.jb51.net canvas实现加载条动画</title> </head> <body> <canv

JS性能优化笔记搜索整理

通过网上查找资料了解关于性能优化方面的内容,现简单整理,仅供大家在优化的过程中参考使用,如有什么问题请及时提出,再做出相应的补充修改. 一. 让代码简洁:一些简略的表达方式也会产生很好的优化 eg:x=x+1;在不影响功能的情况下可以简写为x++; 二. 变量名方法名尽量在不影响语意的情况下简单.(可以选择首字母命名) eg:定义数组的长度可以取名为:ArrLen而不需要取为ArrayLength. 三. 关于JS的循环,循环是一种常用的流程控制. JS提供了三种循环:for(;;).while

网页前端优化之滚动延时加载图片示例

为什么要延时加载呢?页面加载的时候就显示全部的图片不就得了?有必要多此一举吗?答案是肯定的.当要加载的图片或者内容很多时,如果一次性加载完毕,那么整个页面将会加载很久,意味着要用户等待很久,这是对用户不友好的.或许你还会问,那不就做个分页不就得了?其实这种滚动延时加载的技巧正是用来代替手动点击下一页的分页技术.每换一页都要用户点击一次,这也是对用户不友好的.所以才有了滚动延时加载. 我这里把加载图片作为例子,就好像百度图片里的一样,你往下滚动,它就会继续显示下一页的图片. 要求是这样的,比如我要

js性能优化技巧

性能优化:简而言之,就是在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短 http:超文本协议 它的最上层是应用层 传输层 网络层 物理层 请求信息:请求行 请求头 空行 消息体 响应信息:状态行和状态码 使用值类型的ToString方法: 在连接字符串时,经常使用"+"号直接将数字添加到字符串中.这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中.但是装箱操作对性能影响较大,因为在进行这