性能优化,①浏览器第一次访问服务器资源 /in

2019-10-06 作者:小鱼儿主页高手论坛   |   浏览(71)

AMP,来自 Google 的移动页面优化方案

2015/10/12 · HTML5 · AMP

原文出处: imququ(@屈光宇)   

Web 性能优化(Web Performance Optimization,WPO)是一个老生常谈的话题,我也写过很多关于「性能优化」的文章。最近 Google 某个团队推出了一项名为 Accelerated Mobile Pages(AMP)的技术,号称能大大加快移动端页面呈现速度,提高整体体验。本文就带大家认识一下这项新技术。

JavaScript 六种继承方式

2017/06/20 · JavaScript · 继承

原文出处: Xuthus Blog   

继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的。

浏览器 HTTP 缓存原理分析

2015/10/27 · HTML5 · 1 评论 · HTTP

原文出处: 桃子夭夭   

以前项目中遇到了很多浏览器缓存相关的问题,也在网上查过资料,搞过服务器的配置,来确保客户端加载服务器资源的速度和资源有效性。最近仔细看了下http协议中和缓存相关的一些属性,总结一下。

论如何在手机端web前端实现自定义原生控件的样式

2015/10/30 · HTML5 · 原生控件

原文出处: 卖烧烤夫斯基   

手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式。首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样:

android:

图片 1

ios:

图片 2

AMP 介绍

Accelerated Mobile Pages(官网、GitHub),直译成中文是「加速的移动页面」的意思。根据官方说明,AMP 在 Speed Index(首屏展现时间平均值)测试中,性能有 15% ~ 85% 的提升,测试是在模拟 3G 网络环境并模拟 Nexus 5 的条件下完成(详情)。

AMP 如何让页面性能大幅提升暂且搁置一边,先来看看它是什么。根据官网文档得知,AMP 主要由 AMP HTML、AMP Runtime 以及 AMP Components 三部分组成。

原型链

首先得要明白什么是原型链,在一篇文章看懂proto和prototype的关系及区别中讲得非常详细

原型链继承基本思想就是让一个原型对象指向另一个类型的实例

function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function () { return this.property } function SubType() { this.subproperty = false } SubType.prototype = new SuperType() SubType.prototype.getSubValue = function () { return this.subproperty } var instance = new SubType() console.log(instance.getSuperValue()) // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function SuperType() {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType() {
  this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function () {
  return this.subproperty
}
var instance = new SubType()
console.log(instance.getSuperValue()) // true

代码定义了两个类型SuperType和SubType,每个类型分别有一个属性和一个方法,SubType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的。

实现的本质是重写原型对象,代之以一个新类型的实例,那么存在SuperType的实例中的所有属性和方法,现在也存在于SubType.prototype中了。

我们知道,在创建一个实例的时候,实例对象中会有一个内部指针指向创建它的原型,进行关联起来,在这里代码SubType.prototype = new SuperType(),也会在SubType.prototype创建一个内部指针,将SubType.prototype与SuperType关联起来。

所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会顺着这条链一直往上找。

添加方法

在给SubType原型添加方法的时候,如果,父类上也有同样的名字,SubType将会覆盖这个方法,达到重新的目的。 但是这个方法依然存在于父类中。

记住不能以字面量的形式添加,因为,上面说过通过实例继承本质上就是重写,再使用字面量形式,又是一次重写了,但这次重写没有跟父类有任何关联,所以就会导致原型链截断。

function SuperType() { this.property = true } SuperType.prototype.getSuperValue = function () { return this.property } function SubType() { this.subproperty = false } SubType.prototype = new SuperType() SubType.prototype = { getSubValue:function () { return this.subproperty } } var instance = new SubType() console.log(instance.getSuperValue()) // error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType() {
  this.property = true
}
SuperType.prototype.getSuperValue = function () {
  return this.property
}
function SubType() {
  this.subproperty = false
}
SubType.prototype = new SuperType()
SubType.prototype = {
  getSubValue:function () {
   return this.subproperty
  }
}
var instance = new SubType()
console.log(instance.getSuperValue())  // error

问题

单纯的使用原型链继承,主要问题来自包含引用类型值的原型。

function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { } SubType.prototype = new SuperType() var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green", "black"]

1
2
3
4
5
6
7
8
9
10
11
function SuperType() {
  this.colors = ['red', 'blue', 'green']
}
function SubType() {
}
SubType.prototype = new SuperType()
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green", "black"]

在SuperType构造函数定义了一个colors属性,当SubType通过原型链继承后,这个属性就会出现SubType.prototype中,就跟专门创建了SubType.prototype.colors一样,所以会导致SubType的所有实例都会共享这个属性,所以instance1修改colors这个引用类型值,也会反映到instance2中。

浏览器缓存原理

无奈的选择

看完了这些丑陋的界面元素,我们就可以理解当我们把他们暴露在产品同学的眼中时,那种层层的杀气了。可以看到,界面元素十分丑陋,产品兄弟是肯定不会接受的。但是,不得不说这些控件在触发后的效果比pc机上的要炫酷。这其中以apple机的滚筒选择最为出色.以下是它们触发后调用原生控件的效果:

android:

图片 3图片 4图片 5

ios:

图片 6图片 7图片 8

不得不说这些样式原生弹出样式是符合我们设计的原则的,因为它即体现了UI界面的友好和体验度,又不损耗任何web性能,关键是我们什么都不需要做。产品BZJ君看到了,指明要在apple机下要滚筒的效果用来选择日期或者下来单。如果我们不能解决掉界面文本框的样式问题,那么无论后面的效果多炫酷,始终使无法让人接受的。也许你会想花时间写类似的效果?我不否认你可以写出来,但是需要多少时间的工作量呢?也很多人选择了插件的方式。通过jq插件(如果你的项目中没在使用jq,为了这个效果无奈下载jq和其插件)来实现,其实是非常吃力不讨好的事情。一个是插件这种东西出了问题或者变换了需求后它会变得异常的不好扩展,第二个当然是考虑到资源加载,在手机端尤其需要考虑。因此,选择插件是下下策!

AMP HTML

AMP HTML 是 HTML 的子集,在 AMP HTML 中只允许使用有限的标签。例如 <body><article> 这些标签可以直接使用,没有任何限制;有些标签允许有限制的使用,例如 <meta> 标签不能使用 http-equiv 属性;而像 <img><audio> 这样的标签需要替换为 <amp-img><amp-audio> 等 AMP Components;更多的标签如 <frame><form> 不允许使用。

完整说明可以查看官网的 AMP HTML 格式文档。以下是该文档中的 AMP HTML 示例:

XHTML

<html> <head> <meta charset="utf-8"> <title>Sample document</title> <link rel="canonical" href="./regular-html-version.html"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"> <style amp-custom> h1 {color: red} </style> <script type="application/ld json"> { "@context": "", "@type": "NewsArticle", "headline": "Article headline", "image": [ "thumbnail1.jpg" ], "datePublished": "2015-02-05T08:00:00 08:00" } </script> <script async custom-element="amp-carousel" src="; <style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript> <script async src="; </head> <body> <h1>Sample document</h1> <p> Some text <amp-img src=sample.jpg width=300 height=300></amp-img> </p> <amp-ad width=300 height=250 type="a9" data-aax_size="300x250" data-aax_pubname="test123" data-aax_src="302"> </amp-ad> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<html>
<head>
  <meta charset="utf-8">
  <title>Sample document</title>
  <link rel="canonical" href="./regular-html-version.html">
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
  <style amp-custom>
    h1 {color: red}
  </style>
  <script type="application/ld json">
  {
    "@context": "http://schema.org",
    "@type": "NewsArticle",
    "headline": "Article headline",
    "image": [
      "thumbnail1.jpg"
    ],
    "datePublished": "2015-02-05T08:00:00 08:00"
  }
  </script>
  <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
  <style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
  <script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>
<h1>Sample document</h1>
<p>
  Some text
  <amp-img src=sample.jpg width=300 height=300></amp-img>
</p>
<amp-ad width=300 height=250
    type="a9"
    data-aax_size="300x250"
    data-aax_pubname="test123"
    data-aax_src="302">
</amp-ad>
</body>
</html>

可以看出,AMP HTML 与普通 HTML 并没有什么太大区别,上面这段代码可以直接存为 .html 文件,并在浏览器中正常运行。下面简单列举一些格式上的要求:

  • DTD 必须是: <!doctype html>
  • 顶层标签必须包含 AMP 属性,如:<html ⚡> 或 <html amp>(让其他程序能方便地识别出这是 AMP HTML);
  • 必须在 HEAD 区域中放置 <link rel="canonical" href="$SOME_URL" /> 标签,用来指定该文档普通版本的 URL;如果只有一个版本,使用当前 URL 即可(告诉搜索引擎,这是同一个页面不同的版本,否则可能会被判作弊);
  • 必须将 <meta charset="utf-8"> 放置在 HEAD 区域最开始的位置(实际上,普通 HTML 也应该这么做);
  • 必须在 HEAD 区域包含这个 ViewPort:<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
  • 必须将 <script async src="https://cdn.ampproject.org/v0.js"></script> 作为 HEAD 区域最后的元素;
  • 必须在 HEAD 区域包含以下代码:<style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>

借用构造函数

此方法为了解决原型中包含引用类型值所带来的问题。

这种方法的思想就是在子类构造函数的内部调用父类构造函数,可以借助apply()和call()方法来改变对象的执行上下文

function SuperType() { this.colors = ['red', 'blue', 'green'] } function SubType() { // 继承SuperType SuperType.call(this) } var instance1 = new SubType() var instance2 = new SubType() instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"] console.log(instance2.colors) // ["red", "blue", "green"]

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType() {
  this.colors = ['red', 'blue', 'green']
}
function SubType() {
  // 继承SuperType
  SuperType.call(this)
}
var instance1 = new SubType()
var instance2 = new SubType()
instance1.colors.push('black')
console.log(instance1.colors)  // ["red", "blue", "green", "black"]
console.log(instance2.colors) // ["red", "blue", "green"]

在新建SubType实例是调用了SuperType构造函数,这样以来,就会在新SubType对象上执行SuperType函数中定义的所有对象初始化代码。

结果,SubType的每个实例就会具有自己的colors属性的副本了。

传递参数

借助构造函数还有一个优势就是可以传递参数

function SuperType(name) { this.name = name } function SubType() { // 继承SuperType SuperType.call(this, 'Jiang') this.job = 'student' } var instance = new SubType() console.log(instance.name) // Jiang console.log(instance.job) // student

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType(name) {
  this.name = name
}
function SubType() {
  // 继承SuperType
  SuperType.call(this, 'Jiang')
 
  this.job = 'student'
}
var instance = new SubType()
console.log(instance.name)  // Jiang
console.log(instance.job)   // student

问题

如果仅仅借助构造函数,方法都在构造函数中定义,因此函数无法达到复用

文字版描述

①浏览器第一次访问服务器资源 /index.html

在浏览器中没有缓存文件,直接向服务器发送请求。

服务器返回  200 OK,实体中返回 index.html文件内容,并设置一个缓存过期时间,一个文件修改时间,一个根据index.html内容计算出来的实体标记Entity Tag,简称Etag。

浏览器将/index.html路径的请求缓存到本地。

②浏览器第二次访问服务器资源 /index.html

由于本地已经有了此路径下的缓存文件,所以这一次就不直接向服务器发送请求了。

首先进行缓存过期判断。浏览器根据①中设置缓存过期时间判断缓存文件是否过期。

情景一:若没有过期,则不向服务器发送请求,直接使用缓存中的结果,此时我们在浏览器控制台中可以看到  200 OK(from cache) ,此时的情况就是完全使用缓存,浏览器和服务器没有任何交互的。

情景二:若已过期,则向服务器发送请求,此时请求中会带上①中设置的文件修改时间,和Etag

然后进行资源更新判断。服务器根据浏览器传过来的文件修改时间,判断自浏览器上一次请求之后,文件是不是没有被修改过;根据Etag,判断文件内容自上一次请求之后,有没有发生变化

情形一:若两种判断的结论都是文件没有被修改过,则服务器就不给浏览器发index.html的内容了,直接告诉它,文件没有被修改过,你用你那边的缓存吧—— 304 Not Modified,此时浏览器就会从本地缓存中获取index.html的内容。此时的情况叫协议缓存,浏览器和服务器之间有一次请求交互。

情形二:若修改时间和文件内容判断有任意一个没有通过,则服务器会受理此次请求,之后的操作同

①我的文字表达能力可能有限,为了尽量把这个流程描述清楚一点,下面

解决方法

问题来了,既想要弹出层的炫酷效果,又想自定义控件在界面显示的样式。怎么办呢?露珠曾经尝试过最简单的方法去重写css去改变它们的样式,但是即使在google若干小时,也没有找到满意的结果。露珠也尝试过-webkit-appearance属性,但它也显得不尽如人意。况且我们还需要兼容多机型(安卓,苹果,wp?)。无论如何,走改变原始样式的路是行不通的。露珠经过一番思考,找到了自认为非常好的解决方法,也是这篇博文的主题:既然控件在页面的样式不可以改变,那就隐藏它,但是!不是用display:none隐藏,也不是把width和height设置为0,我们希望的是看不到它们的原始样式,而希望保留对它们的tap和focus事件。但是除了以上的方法,还有什么能使它们看不见呢?聪明的你一定想到了,对,就是opacit:0, 通过将控件的不透明度设置为0,我们可以让元素继续让它留在界面上,并且保持随时响应focus事件的状态。我们要做的,是为该控件设置为绝对定位,覆盖在我们自定义样式的一个element上。这样,用户看到的是底下的element,但当他的手去触碰此element时,他实际触碰的是完全透明确留在界面上的原生控件!如下图所示:

图片 9

这还是第一步,接下来我们需要为控件绑定响应事件,大多数情况下我们需要绑定的事件都是onchange,一旦选择完成,就把值复制到自定义的element上去。这样大功告成了!不管你是通过表单或者post提交,你取到的值依然是控件的值,自定义的element只负责显示,不负责业务!

图片 10

本文由小鱼儿玄机30码发布于小鱼儿主页高手论坛,转载请注明出处:性能优化,①浏览器第一次访问服务器资源 /in

关键词: 小鱼儿玄机30码