js css性能优化指南

2020年5月28日17:00:41

官方网址:https://browserdiet.com/#latest-version

另外一个中文版本可能不是最新的,http://shouce.jb51.net/browserdiet/

 

如果我们召集了一大批在大型站点上工作的专家来创建权威的前端性能指南,那该怎么办?

不仅是那些为机器人制作的无聊指南,如果我们做些有趣的事情怎么办?关于如何聚会Briza Bueno (Americanas.com)Davidson Fellipe(Globo.com)Giovanni Keppelen (前Peixe Urbano)Jaydson Gomes (Terra)Marcel Duran (Twitter)Mike Taylor (Opera)Renato Mangini ( Google)SérgioLopes (Caelum)提供最好的参考?

这正是我们所做的!我们会引导您完成创建更快站点的斗争。

— Zeno Rocha,项目负责人。

性能真的重要吗?

??

当然很重要,您知道这一点。那么,为什么我们要继续制作缓慢的网站,导致糟糕的用户体验呢?这是一个社区驱动的实用指南,将向您展示如何使网站更快。让我们不要浪费时间展示百万富翁的业绩案例,让我们直接说吧!

的HTML

避免内联/嵌入代码

您可以通过三种基本方式在页面上包含CSS或JavaScript:

1)内联:例如,在任何HTML标签中,CSS是在style属性内定义的,而JavaScript 是在属性内定义的onclick

2)嵌入式: CSS在<style>标签内定义,JavaScript在<script>标签内;

3)外部:从加载CSS,<link>并从标记src属性加载JavaScript <script>

尽管减少了HTTP请求的数量,但前两个选项实际上增加了HTML文档的大小。但是,当您的资产较小且发出请求的费用较高时,这可能会很有用。在这种情况下,请运行测试以评估速度是否有实际提高。另外,请务必评估页面的用途及其受众:如果您希望人们只访问一次页面,例如对于某些临时广告系列,而您根本不希望回访者访问,则内联/嵌入代码将有助于减少HTTP请求的数量。

>避免在HTML中间手动创作CSS / JS(最好使用工具自动执行此过程)。

第三个选项不仅可以改善代码的组织,还可以使浏览器对其进行缓存。在大多数情况下,最好使用此选项,尤其是在处理大文件和大量页面时。

有用的工具 / 参考

样式在顶部,脚本在底部

当我们将样式表放入时,<head>我们允许页面逐渐呈现,这给我们的用户印象是页面正在快速加载。

<head>
  <meta charset="UTF-8">
  <title>Browser Diet</title>

  <!-- CSS -->
  <link rel="stylesheet" href="style.css" media="all">
</head>

但是,如果我们将它们放在页面的末尾,则页面将呈现为没有样式,直到下载并应用CSS。

怪胎#32

另一方面,在处理JavaScript时,将脚本放置在页面底部很重要,因为脚本在加载和执行时会阻止渲染。

<body>
  <p>Lorem ipsum dolor sit amet.</p>

  <!-- JS -->
  <script src="script.js"></script>
</body>

参考

尝试异步

为了说明此属性如何有助于提高性能,最好了解不使用它时会发生什么。

怪胎#20
<script src="example.js"></script>

以这种形式,页面必须等待脚本被完全下载,解析和执行,然后才能解析和呈现以下任何HTML。这会大大增加页面的加载时间。有时可能需要这种行为,但通常不是。

<script async src="example.js"></script>

该脚本是异步下载的,而页面的其余部分继续被解析。保证下载完成后立即执行脚本。请记住,多个异步脚本将以不特定的顺序执行。

参考

的CSS

缩小样式表

为了保持可读的代码,编写注释并使用缩进是一个好主意:

.center {
  width: 960px;
  margin: 0 auto;
}

/* --- Structure --- */

.intro {
  margin: 100px;
  position: relative;
}

但是对于浏览器,这实际上并不重要。因此,请务必记住通过自动化工具缩小CSS。

.center{width:960px;margin:0 auto}.intro{margin:100px;position:relative}

这将从文件大小中删除字节,从而加快了下载,解析和执行的速度。

对于那些使用预处理器(如SassLessStylus)的处理器可以将已编译的CSS输出配置为最小。

有用的工具 / 参考

合并多个css文件

组织和维护样式的另一种最佳做法是将样式分成模块化组件。

怪胎#9
<link rel="stylesheet" href="structure.css" media="all">
<link rel="stylesheet" href="banner.css" media="all">
<link rel="stylesheet" href="layout.css" media="all">
<link rel="stylesheet" href="component.css" media="all">
<link rel="stylesheet" href="plugin.css" media="all">

但是,这些文件中的每个文件都需要HTTP请求(我们知道浏览器只能并行下载有限数量的资源)。

<link rel="stylesheet" href="main.css" media="all">

因此,结合您的CSS。文件数量较少将导致请求数量减少和加载页面速度加快。

想要两全其美吗?通过构建工具使此过程自动化。

有用的工具 / 参考

优先使用<link>而不是@import

有两种方法可以在页面中包含外部样式表:通过<link>标签:

<link rel="stylesheet" href="style.css">

或通过@import指令(在外部样式表中或内联<style>标记中):

@import url('style.css');

当您通过外部样式表使用第二个选项时,浏览器无法并行下载资产,这会阻止其他资产的下载。

参考

的JAVASCRIPT

异步加载第三方内容

谁从未加载第三方内容来嵌入YouTube视频或“顶/踩”按钮?

怪胎#46

最大的问题是,无论是通过用户的连接还是与托管它们的服务器的连接,这些代码都无法始终高效地传递。或者此服务可能暂时关闭,甚至被用户或其公司的防火墙阻止。

为避免在加载网站或更糟糕的情况下成为关键问题,请锁定整个页面加载,始终异步加载这些代码(或使用Friendly iFrames)。

var script = document.createElement('script'),
    scripts = document.getElementsByTagName('script')[0];
script.async = true;
script.src = url;
scripts.parentNode.insertBefore(script, scripts);

另外,如果您想加载多个第三方窗口小部件,则可以使用此脚本异步加载它们

视频 / 参考

缓存阵列长度

循环无疑是与JavaScript性能相关的最重要的部分之一。尝试优化循环内的逻辑,以便高效地完成每次迭代。

一种方法是存储将要覆盖的数组的大小,因此不必在每次循环时都重新计算它的大小。

var arr = new Array(1000),
    len, i;

for (i = 0; i < arr.length; i++) {
  // Bad - size needs to be recalculated 1000 times
}

for (i = 0, len = arr.length; i < len; i++) {
  // Good - size is calculated only 1 time and then stored
}

>在JSPerf上的结果

>注意: 尽管现代浏览器引擎会自动优化此过程,但仍然是适合仍存在的传统浏览器的良好实践。

在HTML集合的迭代中,例如由其生成的节点列表(NodeListdocument.getElementsByTagName('a')尤其重要。这些集合被认为是“实时的”,即当它们所属的元素发生变化时,它们会自动更新。

var links = document.getElementsByTagName('a'),
    len, i;

for (i = 0; i < links.length; i++) {
  // Bad - each iteration the list of links will be recalculated to see if there was a change
}

for (i = 0, len = links.length; i < len; i++) {
  // Good - the list size is first obtained and stored, then compared each iteration
}

// Terrible: infinite loop example
for (i = 0; i < links.length; i++) {
  document.body.appendChild(document.createElement('a'));
  // each iteration the list of links increases, never satisfying the termination condition of the loop
  // this would not happen if the size of the list was stored and used as a condition
}

参考

避免document.write

使用document.writecause会导致完全依赖页面返回时对页面的依赖。

这种(不好的)做法已经被开发人员废除了多年,但是在某些情况下仍然需要使用它,例如某些JavaScript文件的同步回退。

例如,如果Google的CDN没有响应,则HTML5 Boilerplate使用此技术在本地加载jQuery 

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.0.min.js"><\/script>')</script>

>注意: document.writewindow.onload事件发生期间或之后执行,将替换当前页面的全部内容。

<span>foo</span>
<script>
  window.onload = function() {
    document.write('<span>bar</span>');
  };
</script>

最后一页的结果将仅是bar,而不是预期的foob​​arwindow.onload事件发生后运行时也会发生同样的情况

<span>foo</span>
<script>
  setTimeout(function() {
    document.write('<span>bar</span>');
  }, 1000);
  window.onload = function() {
    // ...
  };
</script>

如果事件发生setTimeout后执行by调度的函数,结果将与前面的示例相同window.onload

参考

最小化重绘和重排

当某些属性或元素发生更改时,如果存在任何重新渲染DOM的过程,则会导致重新绘制和重排。

当更改元素外观而不更改其布局时,将触发重新绘制。妮可•沙利文(Nicole Sullivan)形容这是风格的改变,如改变风格background-color

重排是最昂贵的,因为重排是由更改页面布局(例如更改元素的宽度)引起的。

毫无疑问,应避免过度的重熔和重涂,所以不要这样做:

怪胎#55
var div = document.getElementById("to-measure"),
    lis = document.getElementsByTagName('li'),
    i, len;

for (i = 0, len = lis.length; i < len; i++) {
  lis[i].style.width = div.offsetWidth + 'px';
}

做这个:

var div = document.getElementById("to-measure"),
    lis = document.getElementsByTagName('li'),
    widthToSet = div.offsetWidth,
    i, len;

for (i = 0, len = lis.length; i < len; i++) {
  lis[i].style.width = widthToSet + 'px';
}

设置时style.width,浏览器需要重新计算布局。通常,更改许多元素的样式只会导致一次重排,因为浏览器在需要更新屏幕之前不需要考虑它。但是,在第一个示例中,我们要求offsetWidth,这是元素的layout-width,因此浏览器需要重新计算布局。

如果您需要从页面读取布局数据,则在设置任何更改布局的内容之前,请一并进行处理,如第二个示例所示。

演示 / 参考

避免不必要的dom操作

每当您触摸DOM而无需这样做时,Panda都会死亡。

严重的是,按DOM元素进行浏览的代价很高。尽管JavaScript引擎变得越来越强大和快速,但始终喜欢优化DOM树的查询。

最简单的优化之一是缓存经常访问的DOM元素。例如,与其在循环的每个迭代中查询DOM,不如在查询它的同时将结果保存到变量中,而是使用循环的每个迭代。

// really bad!
for (var i = 0; i < 100; i++) {
  document.getElementById("myList").innerHTML += "<span>" + i + "</span>";
}
// much better :)
var myList = "";

for (var i = 0; i < 100; i++) {
  myList += "<span>" + i + "</span>";
}

document.getElementById("myList").innerHTML = myList;
// much *much* better :)
var myListHTML = document.getElementById("myList").innerHTML;

for (var i = 0; i < 100; i++) {
  myListHTML += "<span>" + i + "</span>";
}

在JSPerf上的结果

缩小脚本

就像CSS一样,为了保持可读性,最好编写注释并使用缩进:

BrowserDiet.app = function() {

  var foo = true;

  return {
    bar: function() {
      // do something
    }
  };

};

但是对于浏览器,这实际上并不重要。因此,请务必记住通过自动化工具来最小化JavaScript。

BrowserDiet.app=function(){var a=!0;return{bar:function(){}}}

这将从文件大小中删除字节,从而加快了下载,解析和执行的速度。

有用的工具 / 参考

将多个js文件合并为一个

组织和维护脚本的另一种最佳做法是将它们分为模块化组件。

怪胎#47
<script src="navbar.js"></script>
<script src="component.js"></script>
<script src="page.js"></script>
<script src="framework.js"></script>
<script src="plugin.js"></script>

但是,这些文件中的每个文件都需要HTTP请求(我们知道浏览器只能并行下载有限数量的资源)。

<script src="main.js"></script>

因此,结合您的JS。文件数量较少将导致请求数量减少和加载页面速度加快。

想要两全其美吗?通过构建工具使此过程自动化。

有用的工具 / 参考

JQUERY的

始终使用最新版本的jquery

jQuery核心团队一直在寻求通过更好的代码可读性,新功能和对现有算法的优化来对库进行改进。

怪胎#36

因此,如果要将其复制到本地文件,请始终使用最新版本的jQuery,该版本始终在此处提供:

http://code.jquery.com/jquery-latest.js

但是请不要<script>标签中引用该URL ,因为将来会有新版本自动测试到您的网站,所以将来可能会出现问题。而是链接到您特别需要的最新版本的jQuery。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

就像明智的Barney Stinson所说,“新总是更好”:P

参考

选择器

选择器是jQuery使用中最重要的问题之一。有许多不同的方式来选择从DOM元素,但并不意味着它们具有相同的性能,可以使用类,ID或类似的方法选择一个元素find()children()

在所有这些方法中,选择一个ID最快,因为它基于本机DOM操作:

$("#foo");

>在JSPerf上的结果

用于代替

原生JavaScript函数的使用几乎总是比jQuery中的更快。因此,不要使用jQuery.each方法,而要使用JavaScript自己的for循环。

但是请注意,即使for in是本机的,在许多情况下它的性能也比差jQuery.each

久经考验的for循环为我们提供了另一个机会,可以通过缓存要迭代的集合的长度来加快处理速度。

for ( var i = 0, len = a.length; i < len; i++ ) {
    e = a[i];
}

使用反向while和反向for循环是在社会上的一个热门话题,并常常被视为迭代的速度最快的形式。但是,通常由于其可读性较差而被避免。

// reverse while
while ( i-- ) {
  // ...
}

// reverse for
for ( var i = array.length; i--; ) {
  // ...
}

JSPerf结果 / 参考

不要总是使用jquery ...

有时,与jQuery相比,原始JavaScript可能更易于使用并且性能更高。

怪胎#6

考虑以下HTML:

<div id="text">Let's change this content</div>

而不是这样做:

$('#text').html('The content has changed').css({
  backgroundColor: 'red',
  color: 'yellow'
});

使用普通的JavaScript:

var text = document.getElementById('text');
text.innerHTML = 'The content has changed';
text.style.backgroundColor = 'red';
text.style.color = 'yellow';

这很简单,而且速度更快。

JSPerf结果 / 参考

图片

使用css精灵

这项技术是关于将各种图像分组到一个文件中的。

CSS Sprite示例

然后使用CSS定位它们。

.icon-foo {
  background-image: url('mySprite.png');
  background-position: -10px -10px;
}

.icon-bar {
  background-image: url('mySprite.png');
  background-position: -5px -5px;
}

结果,您大大减少了HTTP请求的数量,并避免了页面上其他资源的任何潜在延迟。

使用精灵时,请避免在图像之间留太多空白。这不会影响文件的大小,但是会影响内存消耗。

尽管几乎每个人都对Sprite有所了解,但这种技术并未得到广泛使用-可能是由于开发人员未使用自动工具生成Sprite。我们重点介绍了一些可以帮助您解决此问题的方法。

有用的工具 / 参考

数据uri

此技术是使用CSS精灵的替代方法。

一个数据-URI是内联的URI,你通常会指向的内容的方式。在此示例中,我们使用它来内联CSS背景图像的内容,以减少加载页面所需的HTTP请求数量。

之前:

.icon-foo {
  background-image: url('foo.png');
}

后:

.icon-foo {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII%3D');
}

IE8及更高版本的所有浏览器均支持此base64编码技术。

此方法和CSS拼写方法都需要构建时工具才能维护。该方法的优点是不需要手动拼版放置,因为它将在开发过程中将图像保留在单个文件中。

但是,如果图像较大,则具有极大增加HTML / CSS大小的缺点。如果您在HTTP请求期间没有gzip压缩HTML / CSS,则不建议使用此方法,因为这样的开销可能会抵消通过最小化HTTP请求数量而获得的速度提升。

有用的工具 / 参考

不要在标记中重新缩放图像

始终定义图像widthheight属性。这将有助于避免在渲染过程中不必要的重绘和重排。

<img width="100" height="100" src="logo.jpg" alt="Logo">

知道这一点后,拥有700x700px图像的John Q. Developer 决定使用此技术将图像显示为50x50px

开发人员没有意识到的是,数十个不必要的千字节将通过网络发送。

始终牢记:仅仅因为您可以在HTML中定义图像的宽度和高度,并不意味着您应该这样做以缩小大型图像。

参考

优化图像

图像文件包含许多在Web上无用的信息。例如,JPEG照片可以具有来自相机的Exif元数据(日期,相机型号,位置等)。PNG包含有关颜色,元数据的信息,有时甚至包含微型嵌入式缩略图。浏览器不使用这些内容,而导致文件大小膨胀。

有一些用于图像优化的工具可以删除所有这些不必要的数据,并为您提供更纤细的文件而不会降低质量。我们说他们执行无损压缩。

优化图像的另一种方法是以视觉质量为代价对其进行压缩。我们称这些有损优化。例如,导出JPEG时,可以选择质量级别(0到100之间的数字)。考虑性能时,请始终在视觉质量仍可接受的情况下选择尽可能低的数字。另一种常见的有损技术是减少PNG中的调色板或将PNG-24文件转换为PNG-8。

为了提高用户的感知性能,还应该将所有JPEG文件转换为渐进文件。渐进式JPEG具有强大的浏览器支持,创建非常简单,并且没有明显的性能损失。有利的是,该图像会更快地出现在页面上(请参阅demo)。

有用的工具 / 参考

奖金

诊断工具:您最好的朋友

怪胎#43

如果您想涉足网络性能的世界,至关重要的是在浏览器中安装YSlow扩展程序-从现在开始,它们将是您最好的朋友。

或者,如果您更喜欢在线工具,请访问WebPageTestHTTP ArchivePageSpeed网站。

通常,每个网站都会分析您网站的性能并创建一份报告,为您的网站打分,并提供宝贵的建议,以帮助您解决潜在的问题。

今天就这样!

怪胎#31

我们希望阅读本指南后,您的网站可以有所建树。:)

记住,就像生活中的所有事物一样,没有银弹这样的东西应用程序的性能调整是一项值得尝试的尝试,但不应成为所有开发决策的唯一基础-有时您需要权衡成本和收益。

想了解更多?查看我们用来编写本指南参考资料

有建议吗?@BrowserDiet发送推文在Github上发送拉取请求

不要忘了与您的朋友分享,让我们为所有人打造更快的网络。\ o /

 

posted on 2020-05-28 17:02  zh7314  阅读(260)  评论(0编辑  收藏  举报