面试克星!吐血整理前端面试要点难点基础版

前言:恰逢准备找新工做,整理我的学习以及在大厂面试中汇总的基础要点难点,覆盖从计算机基础到框架上层应用,随着前端知识覆盖面愈来愈广,颇有必要在面试前将基础打好,攻克层层面试,仍在更新中,进阶难点版后期更新新文章,祝各位收割 offer。

github 可收藏查看javascript

零.计算机基础

1.线程与进程的区别

进程是资源分配的单位,而线程是系统调度的单位。进程的引入大大地提升了资源的利用率和系统的吞吐量,而引入线程的目的是为了减小程序并发所付出的系统开销。css

  1. 一个程序至少有一个进程,一个进程至少有一个线程
  2. 线程的划分尺度小于进程,使得多线程程序的并发性高
  3. 另外,进程在执行过程当中拥有独立的内存单元,而多个线程共享内存,从而极大地提升了程序的运行效率
  4. 线程在执行过程当中与进程仍是有区别的。每一个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。可是线程不可以独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分能够同时执行。但操做系统并无将多个线程看作多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别

操做系统中常见的进程调度策略有哪几种:html

FCFS(先来先服务),优先级,时间片轮转,多队列、多级反馈队列。前端

进程间的通讯如何实现?html5

如今最多见的进程间通讯的方式有:信号,信号量,消息队列,共享内存,管道。java

信号是使用信号处理器来进行的,信号量是使用P、V操做来实现的。消息队列是比较高级的一种进程间通讯方法,由于它真的能够在进程间传送消息。jquery

2.常见的设计模式

  • 单例模式

单例模式的定义是产生一个类的惟一实例,但js自己是一种“无类”语言。linux

如建立遮罩层:css3

var createMask = function(){
  var mask;
  return function(){
       return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
  }
}()
  • 工厂模式

简单工厂模式是由一个方法来决定到底要建立哪一个类的实例, 而这些实例常常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能肯定, 而是在执行期决定的状况nginx

  • 观察者模式

观察者模式( 又叫发布者-订阅者模式 )应该是最经常使用的模式之一. 在不少语言里都获得大量应用. 包括咱们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.观察者模式能够很好的实现2个模块之间的解耦。

应用: 事件总线EventBus

div.onclick  =  function click (){
   alert ( ''click' )
}
  • 适配器模式

适配器模式的做用很像一个转接口. 原本iphone的充电器是不能直接插在电脑机箱上的, 而经过一个usb转接口就能够了.

在程序里适配器模式也常常用来适配2个接口, 好比你如今正在用一个自定义的js库. 里面有个根据id获取节点的方法$id(). 有天你以为jquery里的$实现得更酷, 但你又不想让你的工程师去学习新的库和语法. 那一个适配器就能让你完成这件事情.

  • 装饰者模式

装饰者模式是一种为函数或类增添特性的技术,它可让咱们在不修改原来对象的基础上,为其增添新的能力和行为。它本质上也是一个函数。

场景:

  1. 若是你须要为类增添特性或职责,但是从类派生子类的解决方法并不太现实的状况下,就应该使用装饰者模式。
  2. 在例子中,咱们并无对原来的Bicycle基类进行修改,所以也不会对原有的代码产生反作用。咱们只是在原有的基础上增添了一些功能。所以,若是想为对象增添特性又不想改变使用该对象的代码的话,则能够采用装饰者模式。

例子:

1.防抖节流函数

2.装饰者模式除了能够应用在类上以外,还能够应用在函数上(其实这就是高阶函数)。好比,咱们想测量函数的执行时间,那么我能够写这么一个装饰器。

  • 代理模式

代理模式的定义是把对一个对象的访问, 交给另外一个代理对象来操做.

  • 桥接模式

桥接模式的做用在于将实现部分和抽象部分分离开来, 以便二者能够独立的变化。在实现api的时候, 桥接模式特别有用。好比最开始的singleton的例子.

var singleton = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply( this, arguments ) );
    }
}
var createMask = singleton( function(){
  return document.body.appendChild( document.createElement('div') );
})

另一个常见的例子就是forEach函数的实现, 用来迭代一个数组.
能够看到, forEach函数并不关心fn里面的具体实现. fn里面的逻辑也不会被forEach函数的改写影响.

forEach = function( ary, fn ){
  for ( var i = 0, l = ary.length; i < l; i++ ){
    var c = ary[ i ];
    if ( fn.call( c, i, c ) === false ){
      return false;
    }
   }
}
  • 外观模式

外观模式提供一个高层接口,这个接口使得客户端或子系统更加方便调用。

var stopEvent = function( e ){   //同时阻止事件默认行为和冒泡
  e.stopPropagation();
  e.preventDefault();
}
  • 访问者模式

GOF官方定义: 访问者模式是表示一个做用于某个对象结构中的各元素的操做。它使能够在不改变各元素的类的前提下定义做用于这些元素的新操做。咱们在使用一些操做对不一样的对象进行处理时,每每会根据不一样的对象选择不一样的处理方法和过程。在实际的代码过程当中,咱们能够发现,若是让全部的操做分散到各个对象中,整个系统会变得难以维护和修改。且增长新的操做一般都要从新编译全部的类。所以,为了解决这个问题,咱们能够将每个类中的相关操做提取出来,包装成一个独立的对象,这个对象咱们就称为访问者(Visitor)。利用访问者,对访问的元素进行某些操做时,只需将此对象做为参数传递给当前访问者,而后,访问者会依据被访问者的具体信息,进行相关的操做。

  • 策略模式

策略模式的意义是定义一系列的算法,把它们一个个封装起来,而且使它们可相互替换。

  • 中介者模式

中介者对象可让各个对象之间不须要显示的相互引用,从而使其耦合松散,并且能够独立的改变它们之间的交互。

  • 迭代器模式

迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不须要暴露该方法中的内部表示。

js中咱们常常会封装一个each函数用来实现迭代器。

  • 组合模式

组合模式又叫部分-总体模式,它将全部对象组合成树形结构。使得用户只须要操做最上层的接口,就能够对全部成员作相同的操做。

  • 备忘录模式

备忘录模式在js中常常用于数据缓存. 好比一个分页控件, 从服务器得到某一页的数据后能够存入缓存。之后再翻回这一页的时候,能够直接使用缓存里的数据而无需再次请求服务器。

3.HTTP/HTTPS,HTTP 状态码,HTTP缓存方案

HTTP

是互联网上应用最为普遍的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它能够使浏览器更加高效,使网络传输减小。

HTTPS

是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。HTTPS协议的主要做用能够分为两种:一种是创建一个信息安全通道,来保证数据传输的安全;另外一种就是确认网站的真实性。

区别

一、https协议须要到ca申请证书,通常免费证书较少,于是须要必定费用。

二、http是超文本传输协议,信息是明文传输,https则是具备安全性的ssl加密传输协议。

三、http和https使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。

四、http的链接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

HTTPS工做原理

客户端发起HTTPS请求->服务端配置(采用HTTPS协议的服务器必需要有一套本身的的数据证书) ->传送证书(至关于公钥) ->客户端解析证书(由客户端TLS完成,验证公钥是否有效,如没有问题就生成一个随机值,而后用证书加密) ->传送加密信息(传送用证书加密后的随机值,至关于客户端与服务端通讯的钥匙)->服务端解密信息(服务端用私钥解密随机值,并对请求内容经过该值进行对称加密) ->传输加密后的信息->客户端解密信息(客户端用以前生成的私钥解密服务端传回来的信息)

创建链接过程

  • HTTP使用TCP三次握手创建链接,客户端和服务器须要交换3个包
  • HTTPS除了TCP的三个包,还要加上ssl握手须要的9个包,因此一共是12个包。

HTTPS 优势:

1.SEO方面

  • Google搜索引擎中对于采用HTTPS加密的网站在搜索结果的排名将会更高。

2.安全性

  • 尽管HTTPS并不是绝对安全,掌握根证书的机构、掌握加密算法的组织一样能够进行中间人形式的攻击,但HTTPS还是现行架构下最安全的解决方案,主要有如下几个好处:

(1)、使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;

(2)、HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程当中不被窃取、改变,确保数据的完整性。

(3)、HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增长了中间人攻击的成本。

HTTPS的缺点

1.SEO方面

  • 使用HTTPS协议会使页面的加载时间延长近50%,增长10%到20%的耗电,此外,HTTPS协议还会影响缓存,增长数据开销和功耗,甚至已有安全措施也会受到影响也会所以而受到影响。
  • 并且HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么做用。

2.经济方面

(1)、SSL证书须要钱,功能越强大的证书费用越高,我的网站、小网站没有必要通常不会用。

(2)、SSL证书一般须要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗(SSL有扩展能够部分解决这个问题,可是比较麻烦,并且要求浏览器、操做系统支持,Windows XP就不支持这个扩展,考虑到XP的装机量,这个特性几乎没用)。

(3)、HTTPS链接缓存不如HTTP高效,大流量网站如非必要也不会采用,流量成本过高。

(4)、HTTPS链接服务器端资源占用高不少,支持访客稍多的网站须要投入更大的成本,若是所有采用HTTPS,基于大部分计算资源闲置的假设的VPS的平均成本会上去。

(5)、HTTPS协议握手阶段比较费时,对网站的相应速度有负面影响,如非必要,没有理由牺牲用户体验

4.HTTP 状态码

100  Continue  继续,通常在发送post请求时,已发送了http header以后服务端将返回此信息,表示确认,以后发送具体参数信息

200  OK   正常返回信息

201  Created  请求成功而且服务器建立了新的资源

202  Accepted  服务器已接受请求,但还没有处理

301  Moved Permanently  请求的网页已永久移动到新位置。

302 Found  临时性重定向。

303 See Other  临时性重定向,且老是使用 GET 请求新的 URI。

304  Not Modified  自从上次请求后,请求的网页未修改过。

400 Bad Request  服务器没法理解请求的格式,客户端不该当尝试再次使用相同的内容发起请求。

401 Unauthorized  请求未受权。

403 Forbidden  禁止访问。

404 Not Found  找不到如何与 URI 相匹配的资源。

500 Internal Server Error  最多见的服务器端错误。

503 Service Unavailable 服务器端暂时没法处理请求(多是过载或维护)。

5.HTTP缓存方案

关于缓存的使用这里介绍两套方案:expires/If-Modified-Since、Cache-Control/Etag;前者是HTTP1.0中的缓存方案,后者是HTTP1.1中缓存方案,若http头部中同时出现两者,后者的优先级更高。

Expires 和 max-age 均可以用来指定文档的过时时间,可是两者有一些细微差异

  1. Expires在HTTP/1.0中已经定义,Cache-Control:max-age在HTTP/1.1中才有定义,为了向下兼容,仅使用max-age不够
  2. Expires指定一个绝对的过时时间(GMT格式),这么作会致使至少2个问题:

2.1客户端和服务器时间不一样步致使Expires的配置出现问题。

2.2很容易在配置后忘记具体的过时时间,致使过时来临出现浪涌现象

  1. max-age 指定的是从文档被访问后的存活时间,这个时间是个相对值(好比:3600s),相对的是文档第一次被请求时服务器记录的Request\_time(请求时间)
  2. Expires 指定的时间能够是相对文件的最后访问时间(Atime)或者修改时间(MTime),而max-age相对对的是文档的请求时间(Atime)
  3. 若是值为 no-cache,那么每次都会访问服务器。若是值为max-age,则在过时以前不会重复访问服务器。

它分为强缓存和协商缓存:

1)浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存若是命中,浏览器直接从本身的缓存中读取资源,不会发请求到服务器。好比某个css文件,若是浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;

2)当强缓存没有命中的时候,浏览器必定会发送一个请求到服务器,经过服务器端依据资源的另一些http header验证这个资源是否命中协商缓存,若是协商缓存命中,服务器会将这个请求返回,可是不会返回这个资源的数据,而是告诉客户端能够直接从缓存中加载这个资源,因而浏览器就又会从本身的缓存中去加载这个资源;

3)强缓存与协商缓存的共同点是:若是命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。

4)当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。

强缓存

是利用Expires或者Cache-Control这两个http response header实现的,它们都用来表示资源在客户端缓存的有效期。

缓存原理是:

1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Expires的header,如:

图片

2)浏览器在接收到这个资源后,会把这个资源连同全部response header一块儿缓存下来(因此缓存命中的请求返回的header并非来自服务器,而是来自以前缓存的header);

3)浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,拿出它的Expires跟当前的请求时间比较,若是请求时间在Expires指定的时间以前,就能命中缓存,不然就不行。

4)若是缓存没有命中,浏览器直接从服务器加载资源时,Expires Header在从新加载的时候会被更新。

Expires是较老的强缓存管理header,因为它是服务器返回的一个绝对时间,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题,好比随意修改下客户端时间,就能影响缓存命中的结果。因此在http1.1的时候,提出了一个新的header,就是Cache-Control,这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示,如:Cache-Control:max-age=315360000,它的缓存原理是:(与 expires相似)

Cache-Control描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,因此相比较Expires,Cache-Control的缓存管理更有效,安全一些。

这两个header能够只启用一个,也能够同时启用,当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires:

图片

强缓存的应用

强缓存是前端性能优化最有力的工具,没有之一,对于有大量静态资源的网页,必定要利用强缓存,提升响应速度。一般的作法是,为这些静态资源所有配置一个超时时间超长的Expires或Cache-Control,这样用户在访问网页时,只会在第一次加载时从服务器请求静态资源,其它时候只要缓存没有失效而且用户没有强制刷新的条件下都会从本身的缓存中加载,好比前面提到过的京东首页缓存的资源,它的缓存过时时间都设置到了2026年:

然而这种缓存配置方式会带来一个新的问题,就是发布时资源更新的问题,好比某一张图片,在用户访问第一个版本的时候已经缓存到了用户的电脑上,当网站发布新版本,替换了这个图片时,已经访问过第一个版本的用户因为缓存的设置,致使在默认的状况下不会请求服务器最新的图片资源,除非他清掉或禁用缓存或者强制刷新,不然就看不到最新的图片效果。

协商缓存

当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,若是协商缓存命中,请求响应返回的http状态为304而且会显示一个Not Modified的字符串,好比你打开京东的首页,按f12打开开发者工具,再按f5刷新页面,查看network,能够看到有很多请求就是命中了协商缓存的:

图片

查看单个请求的Response Header,也能看到304的状态码和Not Modified的字符串,只要看到这个就可说明这个资源是命中了协商缓存,而后从客户端缓存中加载的,而不是服务器最新的资源:

图片

协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的。

**【Last-Modified,If-Modified-Since】**的控制缓存的原理是:

1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间:

图片

2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值:

图片

3)服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,若是没有变化则返回304 Not Modified,可是不会返回资源内容;若是有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,由于既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header:

图片

4)浏览器收到304的响应后,就会从缓存中加载资源。

5)若是协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified Header在从新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值。

【Last-Modified,If-Modified-Since】都是根据服务器时间返回的header,通常来讲,在没有调整服务器时间和篡改客户端缓存的状况下,这两个header配合起来管理协商缓存是很是可靠的,可是有时候也会服务器上资源其实有变化,可是最后修改时间却没有变化的状况,而这种问题又很不容易被定位出来,而当这种状况出现的时候,就会影响协商缓存的可靠性。因此就有了另一对header来管理协商缓存,这对header就是【ETag、If-None-Match】。它们的缓存管理的方式是:

1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上ETag的header,这个header是服务器根据当前请求的资源生成的一个惟一标识,这个惟一标识是一个字符串,只要资源有变化这个串就不一样,跟最后修改时间没有关系,因此能很好的补充Last-Modified的问题:

图片

2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-None-Match的header,这个header的值就是上一次请求时返回的ETag的值:

图片

3)服务器再次收到资源请求时,根据浏览器传过来If-None-Match和而后再根据资源生成一个新的ETag,若是这两个值相同就说明资源没有变化,不然就是有变化;若是没有变化则返回304 Not Modified,可是不会返回资源内容;若是有变化,就正常返回资源内容。与Last-Modified不同的是,当服务器返回304 Not Modified的响应时,因为ETag从新生成过,response header中还会把这个ETag返回,即便这个ETag跟以前的没有变化:

图片

4)浏览器收到304的响应后,就会从缓存中加载资源。

协商缓存的管理

协商缓存跟强缓存不同,强缓存不发请求到服务器,因此有时候资源更新了浏览器还不知道,可是协商缓存会发请求到服务器,因此资源是否更新,服务器确定知道。大部分web服务器都默认开启协商缓存,并且是同时启用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,好比apache:

【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】通常都是同时启用,这是为了处理Last-Modified不可靠的状况。有一种场景须要注意:

分布式系统里多台机器间文件的Last-Modified必须保持一致,以避免负载均衡到不一样机器致使比对失败;

分布式系统尽可能关闭掉ETag(每台机器生成的ETag都会不同);

协商缓存须要配合强缓存使用,你看前面这个截图中,除了Last-Modified这个header,还有强缓存的相关header,由于若是不启用强缓存的话,协商缓存根本没有意义。

其余:

1)当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;

2)当f5刷新网页时,跳过强缓存,可是会检查协商缓存;

大公司的静态资源优化方案,基本上要实现这么几个东西:

  1. 配置超长时间的本地缓存 —— 节省带宽,提升性能
  2. 采用内容摘要做为缓存更新依据 —— 精确的缓存控制
  3. 静态资源CDN部署 —— 优化网络请求
  4. 更资源发布路径实现非覆盖式发布 —— 平滑升级

6.TCP/UDP,有什么区别,说说三次握手四次挥手

IP是Internet Protocol的简称,是网络层的主要协议,做用是提供不可靠、无链接的数据报传送。

TCP**:**可靠,稳定 TCP的可靠体如今TCP在传递数据以前,会有三次握手来创建链接,并且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开链接用来节约系统资源。TCP的缺点: 慢,效率低,占用系统资源高,易被攻击

UDP**:**快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,因此它在传递数据时很是快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。缺点:不可靠,不稳定 由于UDP没有TCP那些可靠的机制,在数据传递时,若是网络质量很差,就会很容易丢包

常见使用TCP协议的应用以下: 浏览器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件传输

UDP: 当对网络通信质量要求不高的时候,要求网络通信速度能尽可能的快,这时就能够使用UDP。 好比,平常生活中,常见使用UDP协议的应用以下: QQ语音 QQ视频 TFTP

TCP传输的三次握手四次挥手策略

为了准确无误地把数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送    后的状况置之不理,它必定会向对方确认是否成功送达。握手过程当中使用了TCP的标志:SYN和ACK。

发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。最后,发送端再回传一个带ACK标志的数据包,表明“握手”结束。

若在握手过程当中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。

图片

  1. 服务端进程准备好接收来自外部的 TCP 链接。而后服务端进程处于LISTEN状态,等待客户端链接请求。
  2. 客户端向服务器发出链接请求,请求中首部同步位 SYN = 1,同时选择一个初始序号 sequence ,简写 seq = x。SYN 报文段不容许携带数据,只消耗一个序号。此时,客户端进入SYN-SEND状态。
  3. 服务器收到客户端链接后,,须要确认客户端的报文段。在确认报文段中,把 SYN 和 ACK 位都置为 1 。确认号是 ack = x + 1,同时也为本身选择一个初始序号 seq = y。请注意,这个报文段也不能携带数据,但一样要消耗掉一个序号。此时,TCP 服务器进入SYN-RECEIVED(同步收到)状态。
  4. 客户端在收到服务器发出的响应后,还须要给出确认链接。确认链接中的 ACK 置为 1 ,序号为 seq = x + 1,确认号为 ack = y + 1。TCP 规定,这个报文段能够携带数据也能够不携带数据,若是不携带数据,那么下一个数据报文段的序号还是 seq = x + 1。这时,客户端进入ESTABLISHED (已链接)状态
  5. 服务器收到客户的确认后,也进入ESTABLISHED状态。

这样三次握手创建链接的阶段就完成了,双方能够直接通讯了。

断开一个TCP链接则须要“四次握手”:

  • 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(固然,在fin包以前发送出去的数据,若是没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),可是,此时主动关闭方还可 以接受数据。
  • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
  • 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,个人数据也发送完了,不会再给你发数据了。
  • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

7.linux 的一些基本命令

企鹅厂比较喜欢问,考察认识的广度。

8.OSI 七层模型

应用层:应用层、表示层、会话层(从上往下)(HTTP、FTP、SMTP、DNS)

传输层(TCP和UDP)

网络层(IP)

物理和数据链路层(以太网)

每一层的做用以下:

物理层:经过媒介传输比特,肯定机械及电气规范(比特Bit)RJ45 、 CLOCK 、 IEEE802.3 (中继器,集线器,网关

数据链路层:将比特组装成帧和点到点的传递(帧Frame)PPP 、 FR 、 HDLC 、 VLAN 、 MAC (网桥,交换机)

网络层:负责数据包从源到宿的传递和网际互连(包PackeT)IP 、 ICMP 、 ARP 、 RARP 、 OSPF 、 IPX 、 RIP 、 IGRP 、 (路由器)

传输层:提供端到端的可靠报文传递和错误恢复(段Segment)TCP 、 UDP 、 SPX

会话层:创建、管理和终止会话(会话协议数据单元SPDU)NFS 、 SQL 、 NETBIOS 、 RPC

表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)JPEG 、 MPEG 、 ASII

应用层:容许访问OSI环境的手段(应用协议数据单元APDU)FTP 、 DNS 、 Telnet 、 SMTP 、 HTTP 、 WWW 、 NFS

图片

各类协议

ICMP协议: 因特网控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。

TFTP协议: 是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。

HTTP协议: 超文本传输协议,是一个属于应用层的面向对象的协议,因为其简捷、快速的方式,适用于分布式超媒体信息系统。

DHCP协议: 动态主机配置协议,是一种让系统得以链接到网络上,并获取所须要的配置参数手段。

9.Http2.0

  • 二进制分帧(Binary Format)

流是链接中的一个虚拟信道,能够承载双向消息传输。每一个流有惟一整数标识符。为了防止两端流ID冲突,客户端发起的流具备奇数ID,服务器端发起的流具备偶数ID。

在二进制分帧层上,http2.0会将全部传输信息分割为更小的消息和帧,并对它们采用二进制格式的编码将其封装,新增的二进制分帧层同时也可以保证http的各类动词,方法,首部都不受影响,兼容上一代http标准。其中,http1.X中的首部信息header封装到Headers帧中,而request body将被封装到Data帧中。

  • 服务端推ServerPush)

服务器能够对一个客户端请求发送多个响应,服务器向客户端推送资源无需客户端明确地请求。而且,服务端推送能把客户端所须要的资源伴随着index.html一块儿发送到客户端,省去了客户端重复请求的步骤。

正由于没有发起请求,创建链接等操做,因此静态资源经过服务端推送的方式能够极大地提高速度。不过与之相比,服务器推送还有一个很大的优点:能够缓存!也让在遵循同源的状况下,不一样页面之间能够共享缓存资源成为可能。

当服务端须要主动推送某个资源时,便会发送一个 Frame Type 为 PUSH\_PROMISE 的 Frame,里面带了 PUSH 须要新建的 Stream ID。意思是告诉客户端:接下来我要用这个 ID 向你发送东西,客户端准备好接着。客户端解析 Frame 时,发现它是一个 PUSH\_PROMISE 类型,便会准备接收服务端要推送的流。

  • 多路复用 (Multiplexing)

在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有必定数量的限制,超过限制数目的请求会被阻塞。这也是为什么一些站点会有多个静态资源 CDN 域名的缘由之一。

而http2.0中的多路复用优化了这一性能。多路复用容许同时经过单一的http/2 链接发起多重的请求-响应消息。有了新的分帧机制后,http/2 再也不依赖多个TCP链接去实现多流并行了。每一个数据流都拆分红不少互不依赖的帧,而这些帧能够交错(乱序发送),还能够分优先级,最后再在另外一端把它们从新组合起来。

http 2.0 链接都是持久化的,并且客户端与服务器之间也只须要一个链接(每一个域名一个链接)便可。http2链接能够承载数十或数百个流的复用,多路复用意味着来自不少流的数据包可以混合在一块儿经过一样链接传输。当到达终点时,再根据不一样帧首部的流标识符从新链接将不一样的数据流进行组装。

  • 头部压缩(HeaderC****ompression)

http1.x的头带有大量信息,并且每次都要重复发送。http/2使用encoder来减小须要传输的header大小,通信双方各自缓存一份头部字段表,既避免了重复header的传输,又减少了须要传输的大小。

事实上,若是请求中不包含首部(例如对同一资源的轮询请求),那么,首部开销就是零字节,此时全部首部都自动使用以前请求发送的首部。

若是首部发生了变化,则只需将变化的部分加入到header帧中,改变的部分会加入到头部字段表中,首部表在 http 2.0 的链接存续期内始终存在,由客户端和服务器共同渐进地更新。

http/2使用的是专门为首部压缩而设计的HPACK②算法。(http/2的HPACK算法使用一份索引表来定义经常使用的http Header,把经常使用的 http Header 存放在表里,请求的时候便只须要发送在表里的索引位置便可。)

  • 请求优先级(Request Priorities)

把http消息分为不少独立帧以后,就能够经过优化这些帧的交错和传输顺序进一步优化性能。每一个流均可以带有一个31比特的优先值:0 表示最高优先级;2的31次方-1 表示最低优先级。

●优先级最高:主要的html

●优先级高:CSS文件

●优先级中:js文件

●优先级低:图片

性能瓶颈

启用http2.0后会给性能带来很大的提高,但同时也会带来新的性能瓶颈。由于如今全部的压力集中在底层一个TCP链接之上,TCP极可能就是下一个性能瓶颈,好比TCP分组的队首阻塞问题,单个TCP packet丢失致使整个链接阻塞,没法逃避,此时全部消息都会受到影响。将来,服务器端针对http 2.0下的TCP配置优化相当重要。

一.JS

1.js 继承

经常使用六种方法:构造函数继承、原型链继承、组合继承、原型式继承、寄生式继承

  • 1构造函数继承

解决了原型继承中的问题,能够实现多继承.

缺点:

实例并非父类的实例,只是子类的实例。只能继承父类的实例属性和方法,不能继承原型属性/方法。

没法实现函数复用,每一个子类都有父类实例函数的副本,影响性能。

// 使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上。
function Animal(){
  this.species = "动物";
}
function Cat(name,color){
  Animal.apply(this, arguments);
  this.name = name;
  this.color = color;
 }
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
  • 2原型链继承

缺点:

来自原型对象的引用类属性是全部实例共享的、

建立子类实例时,没法向父类构造函数传参。

Cat.prototype = new Animal(); 
// 将Cat的prototype对象指向一个Animal的实例
Cat.prototype.constructor = Cat; 
// 本来指向Cat的构造函数,受上一句的影响Cat.prototype.constructor指向Animal,并且每个实例也有一个constructor属性,默认调用prototype对象的constructor属性,这样会致使继承链的絮乱,所以须要手动纠正,将constructor改回为Cat.
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物

js 原型、原型链概念:原型对象也是普通对象,是对象一个自带的隐式 proto 属性,原型也有可能有本身的原型,若是一个原型对象不为 null 的话,则称之为原型链。原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链。

  • 3组合继承
解决上面的问题,**但调用了两次父类构造函数,生成了两份实例,消耗内存**.
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child (name, age) {
    Parent.call(this, name);

    this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('kevin', '18');
  • 4原型式继承

就是 ES5 Object.create 的模拟实现,将传入的对象做为建立的对象的原型。

缺点:

包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承同样。

function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
  • 5寄生式继承

缺点:跟借用构造函数模式同样,每次建立对象都会建立一遍方法。

function createObj (o) {
    var clone = Object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}
  • 6寄生组合式继承

这种方式的高效率体现它只调用了一次 Parent 构造函数,而且所以避免了在 Parent.prototype 上面建立没必要要的、多余的属性。与此同时,原型链还能保持不变;所以,还可以正常使用 instanceof 和 isPrototypeOf。开发人员广泛认为寄生组合式继承是引用类型最理想的继承范式。

function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
// 关键的三步
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
var child1 = new Child('kevin', '18');
console.log(child1);
// 封装后
function prototype(child, parent) {
    var pt = Object.create(parent.prototype);
    pt.constructor = child;
    child.prototype = pt;
}
// 当咱们使用的时候:
prototype(Child, Parent);
  • class 类继承
class Animal {
    constructor(name) {
        this.name = name
    } 
    getName() {
        return this.name
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name)
        this.age = age
    }
}

2.new 操做符具体干了什么,关于 this 的理解及指向问题

this 是在函数被调用时发生的绑定,它指向什么彻底取决于函数在哪里被调用。

一般来讲,做用域一共有两种主要的工做模型。

  • 词法做用域
  • 动态做用域

而 JavaScript 就是采用的词法做用域,也就是在编程阶段,做用域就已经明确下来了。

在 JavaScript 中,影响 this 指向的绑定规则有四种:

  • 默认绑定
  • 隐式绑定
  • 显式绑定
  • new 绑定

1.默认绑定,这是最直接的一种方式,就是不加任何的修饰符直接调用函数

图片

2.隐式绑定,这种状况会发生在调用位置存在「上下文对象」的状况,如:图片

3.显示绑定

这种就是使用 Function.prototype 中的三个方法 call(), apply(), bind() 了。这三个函数,均可以改变函数的 this 指向到指定的对象,不一样之处在于,call() 和 apply() 是当即执行函数,而且接受的参数的形式不一样:

bind 与 call、apply 区别:bind返回的是一个函数,须要调用才能执行,call、apply 直接执行

  • call(this, arg1, arg2, …)
  • apply(this, [arg1, arg2, …]) 而 bind() 则是建立一个新的包装函数,而且返回,而不是马上执行。
  • bind(this, arg1, arg2, …) apply() 接收参数的形式,有助于函数嵌套函数的时候,把 arguments 变量传递到下一层函数中。 4.new 绑定 在 JavaScript 中,全部的函数均可以被 new 调用,这时候这个函数通常会被称为「构造函数」,实际上并不存在所谓「构造函数」,更确切的理解应该是对于函数的「构造调用」。

图片

4.new 绑定

在 JavaScript 中,全部的函数均可以被 new 调用,这时候这个函数通常会被称为「构造函数」,实际上并不存在所谓「构造函数」,更确切的理解应该是对于函数的「构造调用」。

使用 new 来调用函数,会自动执行下面操做:

  1. 建立一个全新的对象。
  2. 将这个对象的\_\_proto\_\_属性指向constructor函数的prototype属性。。
  3. 这个新对象会绑定到函数调用的 this,执行constructor函数。
  4. 若是函数没有返回其余对象,那么 new 表达式中的函数调用会自动返回这个新对象。

图片

**一个例外状况:**当在构造函数返回一个对象时,内部建立出来的新对象就会被返回的对象所覆盖。

function Test(name) {
  this.name = name
  console.log(this) // Test { name: 'yck' }
  return { age: 26 }
}
const t = new Test('yck')
console.log(t) // { age: 26 }
console.log(t.name) // 'undefined'

优先级顺序为:

「new 绑定」 > 「显式绑定」 > 「隐式绑定」 > 「默认绑定。」

因此,this 究竟是什么

this 并非在编写的时候绑定的,而是在运行时绑定的。它的上下文取决于函数调用时的各类条件。

this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。

当一个函数被调用时,会建立一个「执行上下文」,这个上下文会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。this 就是这个记录的一个属性,会在函数执行的过程当中用到。

3.ajax 是怎么建立的,优缺点,如何解决跨域问题,解释下 js 同源策略为何要有,jsonp 怎么防止接口被滥用及安全性问题。

  • ajax建立过程:
  1. 建立 XMLHttpRequest 对象,也就是建立一个异步调用对象
  2. 建立一个新的 HTTP 请求,并指定该 HTTP 请求的方法、URL 及验证信息
  3. 设置响应 HTTP 请求状态变化的函数
  4. 发送 HTTP 请求
  5. 获取异步调用返回的数据
  6. 使用 JavaScript和 DOM 实现局部刷新
var xhr;
if (window.XMLHttpRequest) {
  //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
  xhr = new XMLHttpRequest();
}
else {
  // IE6, IE5 浏览器执行代码
  xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    document.getElementById("myDiv").innerHTML = xhr.responseText;
  }
}
xhr.open("GET", "/try/ajax/ajax_info.txt", true);
xhr.send();
  • XHR enctype 属性规定在发送到服务器以前应该如何对表单数据进行编码

    • application/x-www-form-urlencodedcontentType:'application/x-www-form-urlencoded;charset=UTF-8' data: {username: "John", password: "Boston" }
    • multipart/form-dataprocessData:false, //是否自动将 data 转换为字符串。 contentType:false, // 发送信息至服务器时内容编码类型,经过设置 false 跳过设置默认值。 var formData = new FormData(document.querySelector("#data2")); (form id=“#data2”) data: formData
    • application/jsoncontentType:'application/json;charset=UTF-8', data: JSON.stringify({username: "John", password: "Boston" })
    • text/plaincontentType:'text/plain;charset=UTF-8', processData:false, //是否自动将 data 转换为字符串。 data: "我是一个纯正的文本功能!\r\n我第二行"
    • text/xmlcontentType:'text/xml;charset=UTF-8',"
      <h1>我是标签
      </h1>我是内容
      "
  • ajax 优势

    • 页面局部刷新,用户体验好。
    • 异步通讯,更加快的响应能力。
    • 减小冗余请求,减轻了服务器负担;按需获取数据,节约带宽资源。
    • 基于标准化的并被普遍支持的技术,不须要下载插件或者小程序
  • 缺点

    • ajax干掉了back按钮和加入收藏书签功能,即对浏览器后退机制的破坏。
    • 存在必定的安全问题,AJAX 暴露了与服务器交互的细节。
    • 对搜索引擎的支持比较弱。
    • 破坏了程序的异常机制。
    • 没法用URL直接访问
  • 跨域

1.jsonp 须要目标服务器配合一个callback函数。

2.window.name+iframe 须要目标服务器响应window.name。

3.window.location.hash+iframe 一样须要目标服务器做处理。

4.html5的 postMessage+ifrme 这个也是须要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通信。

5.CORS须要服务器设置header :Access-Control-Allow-Origin。

6.nginx反向代理 这个方法通常不多有人说起,可是他能够不用目标服务器配合,不过须要你搭建一个中转nginx服务器,用于转发请求。

  • jsonp

图片

  • js 同源策略:

同源策略是客户端脚本(尤为是Javascript)的重要的安全度量标准。它最先出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不一样源装载。

这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性。

为何要有同源限制:

咱们举例说明:好比一个黑客程序,他利用Iframe把真正的银行登陆页面嵌到他的页面上,当你使用真实的用户名,密码登陆时,他的页面就能够经过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

get post 区别

  • get参数经过url传递,post放在request body中。
  • get请求在url中传递的参数是有长度限制的,而post没有。
  • get比post更不安全,由于参数直接暴露在url中,因此不能用来传递敏感信息。

    • get请求只能进行url编码,而post支持多种编码方式
    • get请求会浏览器主动cache,而post支持多种编码方式。
    • get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

4. js块级做用域在ES5/ES6中的不一样实现,js 闭包的做用缺陷

从做用域链讲起

首先明确几个概念:

  • JavaScript有函数级做用域,但没有块级做用域。(ES6以前)
  • 当要使用一个变量时,会沿着做用域链一步一步向上查找。

闭包的特性

闭包的主要特性就是能够从外部访问函数内部的属性和方法。

闭包的用途

利用闭包强大的特性,最方便的用途就是实现私有变量和私有方法;另外,由于使用闭包会在内存中保存函数做用域,所以也能保存变量的值。

闭包致使的问题

  • 由于闭包会使得函数中的变量都保存在内存中,如不能及时释放会对性能形成影响。
  • 在IE9如下的浏览器会有内存泄漏的问题。

js setTimeout 闭包问题,连续打印出12345

图片

5.js 垃圾回收机制,什么状况下会发生内存泄漏

与JS中的垃圾回收机制有关,有两种策略来实现垃圾回收:标记清除引用计数。

引用计数:

**早期的回收算法,就是先记下某个变量被引用的总次数,而后当被引用次数为0时,就表示可回收。**问题在于对于根部不可访问即脱离环境的仍存在相互引用的状况,它们的引用次数不为 0,就不能被回收。

标记清除

  • 垃圾回收器获取根并**“标记”**(记住)它们。
  • 而后它访问并“标记”全部来自它们的引用。
  • 而后它访问标记的对象并标记它们的引用。全部被访问的对象都被记住,以便之后再也不访问同一个对象两次。
  • 以此类推,直到有未访问的引用(能够从根访问)为止。
  • 除标记的对象外,全部对象都被删除。

一些优化:

  • 分代回收——对象分为两组:“新对象”和“旧对象”。许多对象出现,完成它们的工做并迅速结 ,它们很快就会被清理干净。那些活得足够久的对象,会变“老”,而且不多接受检查。
  • 增量回收——若是有不少对象,而且咱们试图一次遍历并标记整个对象集,那么可能会花费一些时间,并在执行中会有必定的延迟。所以,引擎试图将垃圾回收分解为多个部分。而后,各个部分分别执行。这须要额外的标记来跟踪变化,这样有不少微小的延迟,而不是很大的延迟。
  • 空闲时间收集——垃圾回收器只在 CPU 空闲时运行,以减小对执行的可能影响。

什么是垃圾?

通常来讲没有被引用的对象就是垃圾,就是要被清除, 有个例外若是几个对象引用造成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。

6.ES6 有哪些新特性,箭头函数和 function 有什么区别

JS箭头函数和function的区别:

  • 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 箭头函数不能够看成构造函数,也就是说,不能够使用new命令,不然会抛出一个错误。
  • 箭头函数不能够使用arguments对象,该对象在函数体内不存在。若是要用,能够用Rest参数代替。
  • 不能够使用yield命令,所以箭头函数不能用做Generator函数。

由于箭头函数没有 this,因此一切试图改变箭头函数this指向都会是无效的,箭头函数的this只取决于定义时的环境。

7.Promise 概念,手写 Promise

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。有了Promise对象,就能够将异步操做以同步操做的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操做更加容易。

  • Promise有三种状态pendingresolvedrejected。状态转换只能是pendingresolved或者pendingrejected;状态一旦转换完成,不能再次转换。
  • Promise拥有一个then方法,用以处理resolvedrejected状态下的值。

实现

class Promise {
  // 定义Promise状态变量,初始值为pending
  status = 'pending';
  // 由于在then方法中须要处理Promise成功或失败时的值,因此须要一个全局变量存储这个值
  data = '';
  // Promise resolve时的回调函数集
  onResolvedCallback = [];
  // Promise reject时的回调函数集
  onRejectedCallback = [];
  // Promise构造函数,传入参数为一个可执行的函数
  constructor(executor) {
    // resolve函数负责把状态转换为resolved
    function resolve(value) {
      this.status = 'resolved';
      this.data = value;
      for (const func of this.onResolvedCallback) {
        func(this.data);
      }
    }
    // reject函数负责把状态转换为rejected
    function reject(reason) {
      this.status = 'rejected';
      this.data = reason;
      for (const func of this.onRejectedCallback) {
        func(this.data);
      }
    }
    // 直接执行executor函数,参数为处理函数resolve, reject。由于executor执行过程有可能会出错,错误状况须要执行reject
    try {
      executor(resolve, reject);
    } catch(e) {
      reject(e)
    }
  }
  /**
    * 拥有一个then方法
    * then方法提供:状态为resolved时的回调函数onResolved,状态为rejected时的回调函数onRejected
    * 返回一个新的Promise
  */
  then(onResolved, onRejected) {
    // 设置then的默认参数,默认参数实现Promise的值的穿透
    onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return e };
    onRejected = typeof onRejected === 'function' ? onRejected : function(e) { throw e };
    let promise2;
    promise2 =  new Promise((resolve, reject) => {
      // 若是状态为resolved,则执行onResolved
      if (this.status === 'resolved') {
        setTimeout(() => {
          try {
            // onResolved/onRejected有返回值则把返回值定义为x
            const x = onResolved(this.data);
            // 执行[[Resolve]](promise2, x)
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      // 若是状态为rejected,则执行onRejected
      if (this.status === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.data);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      // 若是状态为pending,则把处理函数进行存储
      if (this.status = 'pending') {
        this.onResolvedCallback.push(() => {
          setTimeout(() => {
            try {
              const x = onResolved(this.data);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectedCallback.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.data);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return promise2;
  }
  // [[Resolve]](promise2, x)函数
  resolvePromise(promise2, x, resolve, reject) {
    ...
   //简易版
   // 若是x仍然为Promise的状况
    if (x instanceof Promise) {
      // 若是x的状态尚未肯定,那么它是有可能被一个thenable决定最终状态和值,因此须要继续调用resolvePromise
      if (x.status === 'pending') {
        x.then(function(value) {
          resolvePromise(promise2, value, resolve, reject)
        }, reject)
      } else { 
        // 若是x状态已经肯定了,直接取它的状态
        x.then(resolve, reject)
      }
      return
    } else {
      resolve(x)
    }
    ... 
  }

}

核心极简板20行

function Promise(fn) {
  this.cbs = [];
  const resolve = (value) => {
    setTimeout(() => {
      this.data = value;
      this.cbs.forEach((cb) => cb(value));
    });
  }
  fn(resolve);
}
Promise.prototype.then = function (onResolved) {
  return new Promise((resolve) => {
    this.cbs.push(() => {
      const res = onResolved(this.data);
      if (res instanceof Promise) {
        res.then(resolve);
      } else {
        resolve(res);
      }
    });
  });
};

Promise的一些静态方法
Promise.deferredPromise.allPromise.racePromise.resolvePromise.reject

  • Promise.all方法,Promise.all方法接收一个promise数组,返回一个新promise2,并发执行数组中的所有promise,全部promise状态都为resolved时,promise2状态为resolved并返回所有promise结果,结果顺序和promise数组顺序一致。若是有一个promiserejected状态,则整个promise2进入rejected状态。
  • Promise.race方法,Promise.race方法接收一个promise数组, 返回一个新promise2,顺序执行数组中的promise,有一个promise状态肯定,promise2状态即肯定,而且同这个promise的状态一致。
  • Promise.resolve方法/Promise.reject,Promise.resolve用来生成一个rejected完成态的promisePromise.reject用来生成一个rejected失败态的promise
// Promise.all
Promise.all = function(promiseArr) {
    let index = 0, result = []
    return new Promise((resolve, reject) => {
        promiseArr.forEach((p, i) => {
            Promise.resolve(p).then(val => {
                index++
                result[i] = val
                if (index === promiseArr.length) {
                    resolve(result)
                }
            }, err => {
                reject(err)
            })
        })
    })
}

Promise存在哪些缺点。

一、没法取消Promise,一旦新建它就会当即执行,没法中途取消。

二、若是不设置回调函数,Promise内部抛出的错误,不会反应到外部。

三、吞掉错误或异常,错误只能顺序处理,即使在Promise链最后添加catch方法,依然可能存在没法捕捉的错误(catch内部可能会出现错误)

四、阅读代码不是一眼能够看懂,你只会看到一堆then,必须本身在then的回调函数里面理清逻辑。

使用Promise进行顺序(sequence)处理。

一、使用async函数配合await或者使用generator函数配合yield

二、使用promise.then经过for循环或者Array.prototype.reduce实现。

function sequenceTasks(tasks) {
    function recordValue(results, value) {
        results.push(value);
        return results;
    }
    var pushValue = recordValue.bind(null, []);
    return tasks.reduce(function (promise, task) {
        return promise.then(() => task).then(pushValue);
    }, Promise.resolve());
}

Promise链上返回的最后一个Promise出错了怎么办?
catchpromise链式调用的末尾调用,用于捕获链条中的错误信息,可是catch方法内部也可能出现错误,因此有些promise实现中增长了一个方法donedone至关于提供了一个不会出错的catch方法,而且再也不返回一个promise,通常用来结束一个promise链。

8.js 事件流模型 ,事件委托

事件代理:就是利用事件冒泡的原理,只指定一个事件处理程序来管理某一类型的全部事件。目的:减小DOM操做,提升性能。原理:事件冒泡中,事件是从最深的节点开始,而后逐步向上传播事件,那么咱们给最外面的节点添加事件,那么子节点被触发时(如:cilck)都会冒泡到最外层的节点上,因此都会触发。

事件流****模型:**捕获型事件和冒泡型事件。**调用事件处理阶段-》捕获-》目标-》冒泡

捕获性事件应用场景:适用于做全局范围内的监听,这里的全局是相对的全局,相对于某个顶层结点与该结点全部子孙结点造成的集合范围。图片

当事件捕获和事件冒泡一块儿存在的状况,事件又是如何触发呢

  • 对于非target节点则先执行捕获在执行冒泡
  • 对于target节点则是先执行先注册的事件,不管冒泡仍是捕获

9.requestAnimationFrame、setTimeout、setInterval

requestAnimationFrame 方法让咱们能够在下一帧开始时调用指定函数。

以往JS控制的动画大多使用 setInterval 或者 setTimeout 每隔一段时间刷新元素的位置,来达到动画的效果,可是这种方式并不能准确地控制动画帧率,尽管主流的浏览器对于这两个函数实现的动画都有必定的优化,可是这依然没法弥补它们性能问题。主要缘由是由于JavaScript的单线程机制使得其可能在有阻塞的状况下没法精确到毫秒触发。

requestAnimationFrame()方法正是为了知足高性能动画的需求而提供的API,经过setInterval方法控制的动画其调用的间隔由程序员设置,而requestAnimationFrame()无须设置调用间隔, 它自动紧跟浏览器的绘制的帧率(通常浏览器的显示帧率是60fps,差很少每帧间隔16.7ms)

在实际开发中, 固然尽可能使用css动画, 毕竟css动画性能更优。可是对于一些复杂的动画,好比有暂停,继续等复杂交互等动画仍是须要requestAnimationFrame

requestAnimationFrame 无论理回调函数队列,而滚动、触摸这类高触发频率事件的回调可能会在同一帧内触发屡次。因此正确使用 requestAnimationFrame 的姿式是,在同一帧内可能调用屡次 requestAnimationFrame时,要管理回调函数,防止重复绘制动画。

10 JS 数据类型和判断

基本数据类型:number, string, boolean, undefined, BigInt, Symbol, null

引用数据类型:Object

对象类型: Array, Function, Map, Set, WeakMap, WeakSet

特殊对象: RegExp, Date

BigInt 类型能够用任意精度表示整数,能够安全地存储和操做大整数

Symbol 符号,符号类型是惟一的而且是不可修改的,能够用来做为 Object 的 key 值。

判断:

typeof

typeof返回一个表示数据类型的字符串,返回结果包括:number、string、boolean、object、undefined、function。typeof能够对基本类型number、string  、boolean、undefined作出准确的判断(null除外,typeof null===“object”)而对于引用类型,除了function以外返回的都是object。但当咱们须要知道某个对象的具体类型时,typeof就显得有些力不从心了。

instanceof

当咱们须要知道某个对象的具体类型时,能够用运算符 instanceof,instanceof操做符判断左操做数对象的原型链上是否有右边这个构造函数的prototype属性,也就是说指定对象是不是某个构造函数的实例,最后返回布尔值。 检测的咱们用一段伪代码来模拟instanceof内部执行过程.

function instanceOf(left, right) {
    let proto = left.__proto__
    while (true) {
        if (proto === null) return false
        if (proto === right.prototype) {
            return true
        }
        proto = proto.__proto__
    }
}

constructor
constructor属性的做用是,能够得知某个实例对象,究竟是哪个构造函数产生的。可是 constructor 属性易变,不可信赖,这个主要体如今自定义对象上,当开发者重写prototype后,原有的constructor会丢失。

Object.prototype.toString

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上全部对象的类型均可以经过这个方法获取到。

类型转换

  • 强制转换

**转布尔值规则:**undefined、null、false、NaN、''、0、-0都会转换为 false;

其余全部制都转为 true,包括全部对象。

**转数字规则:**true 为1,false、null为0,undefined 为 NaN, symbol 报错,

字符串若是是数字或者进制值就转为数字,不然就 NaN

  • 隐式转换

四则运算中:

只有当加法运算中,其中一方是字符串类型,就会把另外一个也转换为字符串类型

其余运算中,只要其中一方是数字,那么另外一方就转化为数字。

常见

[] == ![]; // true
5 + '1' = '51'
5 - '1' = 4

二.CSS

1.CSS 选择符有哪些,那些属性能够继承,优先级。CSS3 新增伪类。

可继承的样式:

1.font-size 2.font-family

3.color 4.text-indent

不可继承的样式:

1.border 2.padding

3.margin 4.width 5.height

优先级算法:

1.优先级就近原则,同权重状况下样式定义最近者为准;

2.载入样式以最后载入的定位为准;

3.!important >  id > class > tag

4.important 比 内联优先级高,但内联比 id 要高

CSS3新增伪类举例:

p:first-of-type 选择属于其父元素的首个

元素的每一个

元素。

p:last-of-type  选择属于其父元素的最后

元素的每一个

元素。

p:only-of-type  选择属于其父元素惟一的

元素的每一个

元素。

p:only-child    选择属于其父元素的惟一子元素的每一个

元素。

p:nth-child(2)  选择属于其父元素的第二个子元素的每一个

元素。

:enabled :disabled 控制表单控件的禁用状态。

:checked        单选框或复选框被选中

2.CSS3 那些新特性

  1. CSS3实现圆角(border-radius),阴影(box-shadow),
  2. 对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform)
  3. transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);// 旋转,缩放,定位,倾斜
  4. 增长了更多的CSS选择器  多背景 rgba
  5. 在CSS3中惟一引入的伪元素是 ::selection.
  6. 媒体查询,多栏布局
  7. border-image

3.对 BFC/IFC 规范的理解,清除浮动的几种方法

BFC,块级格式化上下文,一个建立了新的BFC的盒子是独立布局的,盒子里面的子元素的样式不会影响到外面的元素。在同一个 BFC 中的两个毗邻的块级盒在垂直方向(和布局方向有关系)的 margin 会发生折叠。

它决定了元素如何对其内容进行定位,以及与其余元素的关系和相互做用。当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照必定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。好比浮动元素会造成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。也能够说BFC就是一个做用范围。

IFC(Inline Formatting Context)即行内格式化上下文

如何产生BFC

当一个HTML元素知足下面条件的任何一点,均可以产生Block Formatting Context:

a、float的值不为none

b、overflow的值不为visible

c、display的值为table-cell, table-caption, inline-block中的任何一个

d、position的值不为relative和static

CSS3触发BFC方式则能够简单描述为:在元素定位非static,relative的状况下触发,float也是一种定位方式。

(3)、BFC的做用与特色

a、不和浮动元素重叠,清除外部浮动,阻止浮动元素覆盖

若是一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个重叠的现象。常规流(也称标准流、普通流)是一个文档在被显示时最多见的布局形态,当float不为none时,position为absolute、fixed时元素将脱离标准流。

4.CSS 尺寸单位,说说 em 与 rem 的区别

  • 绝对长度单位包括:cm厘米(Centimeters)mm毫米(Millimeters)q1/4毫米(quarter-millimeters)in英寸(Inches)pt点、磅(Points)pc派卡(Picas),至关于我国新四号铅字的尺寸px
  • 相对长度单位包括:em,ex,ch,rem,vw相对于视口的宽度,视口被均分为100单位的vwvh相对于视口的高度。视口被均分为100单位的vhvmax,vmin

em 与 rem的区别

  • rem

rem是CSS3新增的一个相对单位(root em,根em),相对于根元素(即html元素)font-size计算值的倍数,只相对于根元素的大小 。rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。

做用:利用rem能够实现简单的响应式布局,能够利用html元素中字体的大小与屏幕间的比值设置font-size的值实现当屏幕分辨率变化时让元素也变化,之前的天猫tmall就使用这种办法

  • em

文本相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(默认16px)。(相对父元素的字体大小倍数)

em(font size of the element)是指相对于父元素的字体大小的单位。它与rem之间其实很类似,区别在。(相对是的HTML元素的字体大,默认16px)

em与rem的重要区别: 它们计算的规则一个是依赖父元素另外一个是依赖根元素计算

5.说说 box-sizing 属性的用法

  • box-sizing:content-box: padding和border不被包含在定义的width和height以内。对象的实际宽度等于设置的width值和border、padding之和,即 ( Element width = width + border + padding,但占有页面位置还要加上margin ) 此属性表现为标准模式下的盒模型。
  • box-sizing:border-box: padding和border被包含在定义的width和height以内。对象的实际宽度就等于设置的width值,即便定义有border和padding也不会改变对象的实际宽度,即 ( Element width = width ) 此属性表现为怪异模式下的盒模型。

6.说说对定位 positon 的理解

使用css布局position很是重要,语法以下:

position:static | relative | absolute | fixed | center | page | sticky

默认值:static,center、page、sticky是CSS3中新增长的值。

  • static

能够认为静态的,默认元素都是静态的定位,对象遵循常规流。此时4个定位偏移属性不会被应用,也就是使用left,right,bottom,top将不会生效。

  • relative

相对定位,对象遵循常规流,而且参照自身在常规流中的位置经过top,right,bottom,left这4个定位偏移属性进行偏移时不会影响常规流中的任何元素。

  • absolute

a、绝对定位,对象脱离常规流,此时偏移属性参照的是离自身最近的定位祖先元素,若是没有定位的祖先元素,则一直回溯到body元素。盒子的偏移位置不影响常规流中的任何元素,其margin不与其余任何margin折叠。

b、元素定位参考的是离自身最近的定位祖先元素,要知足两个条件,第一个是本身的祖先元素,能够是父元素也能够是父元素的父元素,一直找,若是没有则选择body为对照对象。第二个条件是要求祖先元素必须定位,通俗说就是position的属性值为非static都行。

  • fixed

固定定位,与absolute一致,但偏移定位是以窗口为参考。当出现滚动条时,对象不会随着滚动。

  • center

与absolute一致,但偏移定位是以定位祖先元素的中心点为参考。盒子在其包含容器垂直水平居中。(CSS3)

  • page

与absolute一致。元素在分页媒体或者区域块内,元素的包含块始终是初始包含块,不然取决于每一个absolute模式。(CSS3)

  • sticky

对象在常态时遵循常规流。它就像是relative和fixed的合体,当在屏幕中时按常规流排版,当卷动到屏幕外时则表现如fixed。该属性的表现是现实中你见到的吸附效果。(CSS3)

7.垂直水平居中的几种方法

水平居中

  • 行内元素: text-align:center;
  • flex 布局: justify-content: center;
  • margin(width已设置):margin: 0 auto;

垂直居中

  • height: 100px; line-height: 100px;
  • table-cell, vertical-align:middle;
  • flex: align-items: center;

垂直水平居中

  • 设定行高 line-height为height同样数值,仅适用行内元素
.div0{
  width:200px;
  height:150px;
  border:1px solid #000;
  line-height:150px;
  text-align:center;
}
.redbox{
  display:inline-block;
  width:30px;
  height:30px;
  background:#c00;
}
  • 添加伪类元素:CSS里头vertical-align这个属性,这个属性虽然是垂直居中,不过倒是指在元素内的全部元素垂直位置互相居中,并非相对于外框的高度垂直居中。所以,若是有一个方块变成了高度100%,那么其余的方块就会真正的垂直居中。利用::before和::after添加div进到杠杠内,让这个“伪”div的高度100%
.div0::before{
  content:'';
  width:0;
  height:100%;
  display:inline-block;
  position:relative;
  vertical-align:middle;
  background:#f00;
}
  • calc 动态计算:咱们只要让要居中的div的top属性,与上方的距离是“50%的外框高度+ 50%的div高度”,就能够作到垂直居中,至于为何不用margin-top,由于margin相对的是水平宽度,必需要用top才会正确。
.redbox{ 
  width:30px;
  height:30px; 
  background:#c00; 
  float:left; 
  top:calc(50% - 15px); 
  margin-left:calc(50% - 45px); 
}
  • 使用表格或伪装表格:在表格这个HTML里面经常使用的DOM里头,要实现垂直居中是至关容易的,只须要下一行vertical-align:middle就能够
  • transform:利用transform里头的translateY(改变垂直的位移,若是使用百分比为单位,则是以元素自己的长宽为基准),搭配元素自己的top属性,就能够作出垂直居中的效果,比较须要注意的地方是,子元素必需要加上position:relative
  • 绝对定位: 绝对定位就是CSS里头的position:absolute,利用绝对位置来指定,但垂直居中的作法又和咱们正统的绝对位置不太相同,是要将上下左右的数值都设为0,再搭配一个margin:auto,就能够办到垂直居中,不过要特别注意的是,设定绝对定位的子元素,其父元素的position必需要指定为relative
.use-absolute{
    position: relative;
    width:200px;
    height:150px;
    border:1px solid #000;
}
.use-absolute div{
    position: absolute;
    width:100px;
    height:50px;
    top:0;
    right:0;
    bottom:0;
    left:0;
    margin:auto;
    background:#f60;
}

flexbox: 使用align-items或align-content的属性

8.常见的页面布局的方式有哪些

方式:双飞翼、多栏、弹性、流式、瀑布流、响应式布局

  • 双飞翼布局

经典三列布局,也叫作圣杯布局【Holy Grail of Layouts】是Kevin Cornell在2006年提出的一个布局模型概念,在国内最先是由淘宝UED的工程师传播开来,在中国也有叫法是双飞翼布局,它的布局要求有几点:

a、三列布局,中间宽度自适应,两边定宽;

b、中间栏要在浏览器中优先展现渲染;

c、容许任意列的高度最高;

d、要求只用一个额外的DIV标签;

e、要求用最简单的CSS、最少的HACK语句;

在不增长额外标签的状况下,圣杯布局已经很是完美,圣杯布局使用了相对定位,之后布局是有局限性的,并且宽度控制要改的地方也多。在淘宝UED(User Experience Design)探讨下,增长多一个div就能够不用相对布局了,只用到了浮动和负边距,这就是咱们所说的双飞翼布局。

  • 多栏布局

a、栏栅格系统:就是利用浮动实现的多栏布局,在bootstrap中用的很是多。

b、多列布局:栅格系统并无真正实现分栏效果(如word中的分栏),CSS3为了知足这个要求增长了多列布局模块

  • 弹性布局(Flexbox)

CSS3引入了一种新的布局模式——Flexbox布局,即伸缩布局盒模型(Flexible Box),用来提供一个更加有效的方式制定、调整和分布一个容器里项目布局,即便它们的大小是未知或者动态的,这里简称为Flex。Flexbox布局经常使用于设计比较复杂的页面,能够轻松的实现屏幕和浏览器窗口大小发生变化时保持元素的相对位置和大小不变,同时减小了依赖于浮动布局实现元素位置的定义以及重置元素的大小。

Flexbox布局在定义伸缩项目大小时伸缩容器会预留一些可用空间,让你能够调节伸缩项目的相对大小和位置。例如,你能够确保伸缩容器中的多余空间平均分配多个伸缩项目,固然,若是你的伸缩容器没有足够大的空间放置伸缩项目时,浏览器会根据必定的比例减小伸缩项目的大小,使其不溢出伸缩容器。

综合而言,Flexbox布局功能主要具备如下几点:

a、屏幕和浏览器窗口大小发生改变也能够灵活调整布局;

b、能够指定伸缩项目沿着主轴或侧轴按比例分配额外空间(伸缩容器额外空间),从而调整伸缩项目的大小;

c、能够指定伸缩项目沿着主轴或侧轴将伸缩容器额外空间,分配到伸缩项目以前、以后或之间;

d、能够指定如何将垂直于元素布局轴的额外空间分布到该元素的周围;

e、能够控制元素在页面上的布局方向;

f、能够按照不一样于文档对象模型(DOM)所指定排序方式对屏幕上的元素从新排序。也就是说能够在浏览器渲染中不按照文档流前后顺序重排伸缩项目顺序。

  • 瀑布流布局

瀑布流布局是流式布局的一种。是当下比较流行的一种网站页面布局,视觉表现为良莠不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最先采用此布局的网站是Pinterest,逐渐在国内流行开来。

优势

a、有效的下降了界面复杂度,节省了空间:咱们再也不须要臃肿复杂的页码导航连接或按钮了。

b、对触屏设备来讲,交互方式更符合直觉:在移动应用的交互环境当中,经过向上滑动进行滚屏的操做已经成为最基本的用户习惯,并且所须要的操做精准程度远远低于点击连接或按钮。

c、更高的参与度:以上两点所带来的交互便捷性能够使用户将注意力更多的集中在内容而不是操做上,从而让他们更乐于沉浸在探索与浏览当中。

缺点

a、有限的用例:无限滚动的方式只适用于某些特定类型产品当中一部分特定类型的内容。 例如,在电商网站当中,用户时常须要在商品列表与详情页面之间切换,这种状况下,传统的、带有页码导航的方式能够帮助用户更稳妥和准确的回到某个特定的列表页面当中。

b、额外的复杂度:那些用来打造无限滚动的JS库虽然都自称很容易使用,但你总会须要在本身的产品中进行不一样程度的定制化处理,以知足大家本身的需求;另外这些JS库在浏览器和设备兼容性等方面的表现也良莠不齐,你必须作好充分的测试与调整工做。

c、再见了,页脚:若是使用了比较典型的无限滚动加载模式,这就意味着你能够和页脚说拜拜了。 最好考虑一下页脚对于你的网站,特别是用户的重要性;若是其中确实有比较重要的内容或连接,那么最好换一种更传统和稳妥的方式。千万不要耍弄你的用户,当他们一次次的浏览到页面底部,看到页脚,却由于自动加载的内容忽然出现而不管如何都没法点击页脚中的连接时,他们会变的愈加愤怒。

d、集中在一页当中动态加载数据,与一页一页的输出相比,究竟那种方式更利于SEO,这是你必须考虑的问题。对于某些以类型网站来讲,在这方面进行冒险是很不划算的。

e、关于页面数量的印象:其实站在用户的角度来看,这一点并不是负面;不过,若是对于你的网站来讲,经过更多的内容页面展现更多的相关信息(包括广告)是很重要的策略,那么单页无限滚动的方式对你并不适用。

  • 流式布局(Fluid)

固定布局和流式布局在网页设计中最经常使用的两种布局方式。固定布局能呈现网页的原始设计效果,流式布局则不受窗口宽度影响,流式布局使用百分比宽度来限定布局元素,这样能够根据客户端分辨率的大小来进行合理的显示。

  • 响应式布局

响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站可以兼容多个终端——而不是为每一个终端作一个特定的版本。这个概念是为解决移动互联网浏览而诞生的。响应式布局能够为不一样终端的用户提供更加温馨的界面和更好的用户体验,并且随着目前大屏幕移动设备的普及,用“大势所趋”来形容也不为过。随着愈来愈多的设计师采用这个技术,咱们不只看到不少的创新,还看到了一些成形的模式。

优势

a、面对不一样分辨率设备灵活性强

b、可以快捷解决多设备显示适应问题

缺点

a、兼容各类设备工做量大,效率低下

b、代码累赘,会出现隐藏无用的元素,加载时间加长

c、其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果

d、必定程度上改变了网站原有的布局结构,会出现用户混淆的状况

两栏布局,左侧定宽,右侧自适应

<div id="wrapper1">
  <div class="left">
    左边固定宽度,高度不固定 </br> </br></br></br>高度有可能会很小,也可能很大。
  </div>
  <div class="main">
    这里的内容可能比左侧高,也可能比左侧低。宽度须要自适应。</br>
    基本的样式是,两个div相距20px, 左侧div宽 120px
  </div>
</div>

1.双 inline-block 方法

缺点**:**

  • 须要知道左侧盒子的宽度,两个盒子的距离,还要设置各个元素的box-sizing
  • 须要消除空格字符的影响
  • 须要设置vertical-align: top知足顶端对齐。
#wrapper1 {
  box-sizing: content-box;
  border: 1px solid red;
  padding: 15px 20px;
  font-size: 0; /*消除空格影响*/
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;
  display: inline-block;
  font-size: 14px;
  vertical-align: top; /* 顶端对齐*/
}
#wrapper1 .left {
  width: 200px;
}
#wrapper1 .main {
  width: calc(100% - 200px);
}

2.双 float 方法
缺点**:**

  • 须要知道左侧盒子的宽度,两个盒子的距离,还要设置各个元素的box-sizing。
  • 父元素须要清除浮动。
#wrapper1 {
  box-sizing: content-box;
  border: 1px solid red;
  padding: 15px 20px;

  overflow: auto;
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;

  float: left;
}
#wrapper1 .left {
  width: 200px;
}
#wrapper1 .main {
  width: calc(100% - 200px);
}

3.使用 float + margin-left 的方法

#wrapper1 {
  box-sizing: border-box;
  border: 1px solid red;
  padding: 15px 20px;

  overflow: hidden;
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;
}
#wrapper1 .left {
   float: left;
}
#wrapper1 .main {
   margin-left: 242px
}

4.使用 float + BFC 的方法
缺点**:**

  • 父元素须要清除浮动

正常流中创建新的块格式化上下文的元素(例如除'visible'以外的'overflow'的元素)不能与元素自己相同的块格式上下文中的任何浮点的边界框重叠。

#wrapper1 {
  box-sizing: content-box;
  border: 1px solid red;
  padding: 15px 20px;

  overflow: auto;
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;
}
#wrapper1 .left {
  float: left;
}
#wrapper1 .main {
  overflow: auto;
}

5.使用 flex 方法
须要注意的是,flex容器的一个默认属性值:align-items: stretch;。这个属性致使了列等高的效果。 为了让两个盒子高度自动,须要设置: align-items: flex-start;

#wrapper1 {
  box-sizing: content-box;
  border: 1px solid red;
  padding: 15px 20px;

  display: flex;
  align-items: flex-start;
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;
}
#wrapper1 .left {
   flex: 0 0 auto;   //[ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
#wrapper1 .main {
   flex: 1 1 auto;
}

6.使用 absulute + margin-left 的方法
缺点**:**

  • 使用了绝对定位,如果用在某个div中,须要更改父容器的position。
  • 没有清除浮动的方法,若左侧盒子高于右侧盒子,就会超出父容器的高度。所以只能经过设置父容器的min-height来放置这种状况。
#wrapper1 {
  box-sizing: border-box;
  border: 1px solid red;
  padding: 15px 20px;

  min-height: 300px;
}
#wrapper1 .left, .main {
  box-sizing: border-box;
  border: 1px solid blue;
}
#wrapper1 .left {
   position: absolute;
}
#wrapper1 .main {
   margin-left: 242px
}

9.Sass 有什么特性

  • 变量:容许使用变量,全部变量以$开头,若是变量须要镶嵌在字符串之中,就必须须要写在#{}之中。
  • 计算功能:容许代码中直接使用算式
  • 嵌套:容许直接在选择器中嵌套
  • &嵌套:嵌套代码中能够使用 & 直接引用父元素
  • @extend. 继承:容许一个选择器继承另外一个选择器
  • @mixin: 可定义可重用代码块,后续能够经过 @include 复用
  • @import: 能够插入外部文件
  • 提供注释:标准 /comment/ 回报率到编译后的文件;单行注释 //comment, 只保留在sass源文件中,编译后删除
  1. css 动画,Animation特性

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

( 名称、长度、如何完成一周期、延迟、次数、是否轮流反向播放、不播放时样式、动画播放过程当中可能会忽然中止指定动画是否正在运行或暂停)

  • animation-name 规定须要绑定到选择器的 keyframe 名称
  • animation-duration 规定完成动画所花费的时间,以秒或毫秒计
  • animation-timing-function 规定动画的速度曲线
  • animation-delay 规定在动画开始以前的延迟
  • animation-iteration-count 规定动画应该播放的次数
  • animation-direction 规定是否应该轮流反向播放动画

咱们还须要用keyframes关键字

@keyframes rainbow {
  0% { background: #c00; }
  50% { background: orange; }
  100% { background: yellowgreen; }
}

11 css 实现 0.5px border

大体原理是:经过 css3插入一个伪元素,该元素宽度为父级2倍,高度为1px,而后经过css3缩放将其缩小一倍,从而实现一个 0.5 px 的边框。

.content:before {
    content: ‘’;
    position:absolute;
    width:200%;
    height: 1px;
    border-bottom: 1px solid #000;
    transform-origin: 0, 0; -webkit-transform-origin
    transform: scale(.5,.5); -webkit-transform
    box-sizing: border-box; -webkit-boxsizing
}

12 css 实现三角形

图片 #triangle-up {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}
图片 #triangle-topleft {
width: 0;
height: 0;
border-top: 100px solid red;
border-right: 100px solid transparent;
}

13 如何获取和设置盒子的宽高

//第一种
dom.style.width/height //只能获取内联样式的元素宽高
//第二种
dom.currentStyle.width/height //只有IE浏览器支持
//第三种
dom.getComputedStyle(Dom).width/height //只有浏览器渲染后才能获取 兼容好
//第四种
dom.getBoundingClientRect().width/height //计算一个元素的绝对位置(相对于视窗左上角) 能拿到元素的left、right、width、height

三.HTML

1.浏览器存储 cookie、session、sessionStorage、localStorage

Cookie

  • 每一个特定的域名下最多生成20个cookie
  • cookie的最大大约为4096字节,为了兼容性,通常不能超过4095字节。

优势:

极高的扩展性和可用性

1.经过良好的编程,控制保存在cookie中的session对象的大小。

2.经过加密和安全传输技术(SSL),减小cookie被破解的可能性。

3.只在cookie中存放不敏感数据,即便被盗也不会有重大损失。

4.控制cookie的生命期,使之不会永远有效。偷盗者极可能拿到一个过时的cookie。

缺点

1.Cookie数量和长度的限制。每一个domain最多只能有20条cookie,每一个cookie长度不能超过4KB,不然会被截掉。

2.安全性问题。若是cookie被人拦截了,那人就能够取得全部的session信息。即便加密也与事无补,由于拦截者并不须要知道cookie的意义,他只要原样转发cookie就能够达到目的了。

3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,咱们须要在服务器端保存一个计数器。若是咱们把这个计数器保存在客户端,那么它起不到任何做用。

属性:

name| string : 该Cookie的名称。Cookie一旦建立,名称便不可更改

value| object :该Cookie的值。若是值为Unicode字符,须要为字符编码。若是值为二进制数据,则须要使用BASE64编码

maxAge| int : 该Cookie失效的时间,单位秒。若是为正数,则该Cookie在maxAge秒以后失效。若是为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。若是为0,表示删除该Cookie。默认为–1

secure| boolean : 该Cookie是否仅被使用安全协议传输。https,只在使用SSL安全链接的状况下才会把cookie发送到服务器

**path |string:**该Cookie的使用路径。请求URL中包含这个路径才会把cookie发送到服务器。若是设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序能够访问该Cookie。若是设置为“/”,则本域名下contextPath均可以访问该Cookie。注意最后一个字符必须为“/”

domain| string : 能够访问该Cookie的域名。若是设置为“.google.com”,则全部以“google.com”结尾的域名均可以访问该Cookie。注意第一个字符必须为“.”

comment| string : 该Cookie的用处说明。

version| int : 该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

**httponly |  boolean :**表示此cookie必须用于http或https传输。这意味着,浏览器脚本,好比javascript中,是不容许访问操做此cookie的。以防范跨站脚本攻击(XSS)。

操做:

1.Cookie并不提供修改、删除操做。若是要修改某个Cookie,只须要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。

2.若是要删除某个Cookie,只须要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数表明其余的意义。

  • 永久登陆案例:

    • 一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。(高风险)
    • 若是不但愿保存密码,还能够把登陆的时间戳保存到Cookie与数据库中,到时只验证用户名与登陆时间戳就能够了。
    • 实现方式是把帐号按照必定的规则加密后,连同帐号一块保存到Cookie中。下次访问时只须要判断帐号的加密规则是否正确便可。本例把帐号保存到名为account的Cookie中,把帐号连同密钥用MD1算法加密后保存到名为ssid的Cookie中。验证时验证Cookie中的帐号与密钥加密后是否与Cookie中的ssid相等。

LocalStorage

**+**永久存储

+单个域名存储量比较大(推荐5MB,各浏览器不一样)

**+**整体数量无限制

SessionStorage

+只在Session内有效

**+**存储量更大(推荐没有限制,可是实际上各浏览器也不一样)

2.HTML 5 有哪些新特性

主要是关于图像、位置、存储、多任务等功能的增长。

  • 拖拽释放 API(Drag and drop)
  • 语义化更好的内容标签(header,nav,footer,aside,article,section)
  • 音频、视频API(audio,video)
  • 画布 API (Canvas)
  • 地理 API (Geolocation)
  • 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
  • sessionStorage 的数据在浏览器关闭后自动删除
  • 表单控件,calendar、date、time、email、url、search
  • 新的技术 webworker, websocket, Geolocation

移除的元素:

  1. 纯表现的元素:basefont,big,center,font, s,strike,tt,u;
  2. 对可用性产生负面影响的元素:frame,frameset,noframes;

3.iframe 的优缺点

  • 优势
  1. 解决加载缓慢的第三方内容如图表和广告等的加载问题
  2. Security sandbox
  3. 并行加载脚本
  • 缺点
  1. iframe 会阻塞主页面的 onload 事件
  2. 搜索引擎的检索程序没法解读这种页面,不利于 SEO
  3. iframe 和主页面共享链接池,而浏览器对相同域的链接有限制,因此会影响页面的并行加载

避免手段 若是使用 iframe,最好经过 js 动态给 iframe 添加 src 属性值。

4.Canvas 与 SVG 的区别

Canvas SVG
Canvas是基于像素的位图,依赖分辨率 SVG倒是基于矢量图形,不依赖分辨率
Canvas是基于HTML canvas标签,经过宿主提供的Javascript API对整个画布进行操做的 SVG则是基于XML元素的,历史久远
Canvas没有图层的概念,全部的修改整个画布都要从新渲染 SVG则能够对单独的标签进行修改
关于动画,Canvas更适合作基于位图的动画 而SVG则适合图表的展现
不能被引擎抓取 能够被引擎抓取
Canvas 可以以 .png 或 .jpg 格式保存结果图像;可以引入 .png 或 .jpg格式的图片 SVG 不能以 .png 或 .jpg 格式保存结果图像;不能引入 .png 或 .jpg格式的图片
Canvas 不支持事件处理器(一旦图形被绘制完成,它就不会继续获得浏览器的关注。若是其位置发生变化,那么整个场景也须要从新绘制,包括任何或许已被图形覆盖的对象。) SVG 支持事件处理器(SVG DOM 中的每一个元素都是可用的。您能够为某个元素附加 JavaScript 事件处理器。每一个被绘制的图形均被视为对象。若是 SVG 对象的属性发生变化,那么浏览器可以自动重现图形。)
最适合图像密集型的游戏,其中的许多对象会被频繁重绘 不适合游戏应用

5.js 脚本延迟加载方式有哪些

  1. defer和async
  2. 动态建立DOM方式(建立script,插入到DOM中,加载完毕后callBack)
  3. 按需异步载入js

script 加载中的 async 与 defer 的区别

  • async 与 defer 共同点是采用异步的下载方式,不会阻塞 html 的解析
  • 不一样点在于 async 下载完仍是会当即执行,defer 则是会在 html 解析完去执行,而 js 的执行仍是会阻塞html 的解析的。
  • 缺点:带有async 或者 defer属性的脚本执行也不必定按照顺序执行,有风险,所以确保二者之间互不依赖很是重要。(HTML5规范要求脚本按照它们出现的前后顺序执行,所以第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于DOMContentLoaded事件执行。在现实当中,延迟脚本并不必定会按照顺序执行,也不必定会在DOMContentLoad时间触发前执行,所以最好只包含一个延迟脚本。)

图片

DOMContentLoaded, onload

  • DOMContentLoaded 当初始的 HTML 文档被彻底加载和解析完成以后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。咱们能够在这个阶段使用 JS 去访问元素。 async 的脚本可能尚未执行。

    • 带有 defer 的脚本会在页面加载和解析完毕后执行,恰好在 DOMContentLoaded 以前执行。
    • 图片及其余资源文件可能还在下载中。
  • load 应该仅用于检测一个彻底加载的页面 当一个资源及其依赖资源已完成加载时,将触发load事件。
  • beforeunload 在用户即将离开页面时触发,它返回一个字符串,浏览器会向用户展现并询问这个字符串以肯定是否离开。
  • unload 在用户已经离开时触发,咱们在这个阶段仅能够作一些没有延迟的操做,因为种种限制,不多被使用。
  • document.readyState 表征页面的加载状态,能够在 readystatechange 中追踪页面的变化状态:

    • loading —— 页面正在加载中。
    • interactive —— 页面解析完毕,时间上和 DOMContentLoaded 同时发生,不过顺序在它以前。
    • complete —— 页面上的资源都已加载完毕,时间上和 window.onload 同时发生,不过顺序在他以前。

6.对于 web 性能优化的方法及理解(雅虎网站性能优化 34 条守则)

一个http请求绝大多数的时间消耗在了创建链接跟等待的时间,优化的方法是减小http请求。

  1. 尽量的减小 HTTP 的请求数 content
  2. 使用 CDN(Content Delivery Network)内容分发网络 server
  3. 添加 Expires 头(或者 Cache-control ) server
  4. Gzip 组件 server
  5. 将 CSS 样式放在页面的上方 css
  6. 将脚本移动到底部(包括内联的) javascript
  7. 避免使用 CSS 中的 Expressions css
  8. 将 JavaScript 和 CSS 独立成外部文件 javascript css
  9. 减小 DNS 查询 content
  10. 压缩 JavaScript 和 CSS (包括内联的) javascript css
  11. 避免重定向 server
  12. 移除重复的脚本 javascript
  13. 配置实体标签(ETags) css
  14. 使 AJAX 缓存

雅虎团队经验:网站页面性能优化的34条黄金守则

一、尽可能减小HTTP请求次数

终端用户响应的时间中,有80%用于下载各项内容。这部分时间包括下载页面中的图像、样式表、脚本、Flash等。经过减小页面中的元素能够减小HTTP请求的次数。这是提升网页速度的关键步骤。

减小页面组件的方法其实就是简化页面设计。那么有没有一种方法既能保持页面内容的丰富性又能达到加快响应时间的目的呢?这里有几条减小HTTP请求次数同时又可能保持页面内容丰富的技术。

合并文件是经过把全部的脚本放到一个文件中来减小HTTP请求的方法,如能够简单地把全部的CSS文件都放入一个样式表中。当脚本或者样式表在不一样页面中使用时须要作不一样的修改,这可能会相对麻烦点,但即使如此也要把这个方法做为改善页面性能的重要一步。

CSS Sprites是减小图像请求的有效方法。把全部的背景图像都放到一个图片文件中,而后经过CSS的background-image和background-position属性来显示图片的不一样部分;

图片地图是把多张图片整合到一张图片中。虽然文件的整体大小不会改变,可是能够减小HTTP请求次数。图片地图只有在图片的全部组成部分在页面中是紧挨在一块儿的时候才能使用,如导航栏。肯定图片的坐标和可能会比较繁琐且容易出错,同时使用图片地图导航也不具备可读性,所以不推荐这种方法;

内联图像是使用data:URL scheme的方法把图像数据加载页面中。这可能会增长页面的大小。把内联图像放到样式表(可缓存)中能够减小HTTP请求同时又避免增长页面文件的大小。可是内联图像如今尚未获得主流浏览器的支持。

减小页面的HTTP请求次数是你首先要作的一步。这是改进首次访问用户等待时间的最重要的方法。如同Tenni Theurer的他的博客Browser Cahe Usage - Exposed!中所说,HTTP请求在无缓存状况下占去了40%到60%的响应时间。让那些初次访问你网站的人得到更加快速的体验吧!

二、减小DNS查找次数

域名系统(DNS)提供了域名和IP的对应关系,就像电话本中人名和他们的电话号码的关系同样。当你在浏览器地址栏中输入www.dudo.org时,DNS解析服务器就会返回这个域名对应的IP地址。DNS解析的过程一样也是须要时间的。通常状况下返回给定域名对应的IP地址会花费20到120毫秒的时间。并且在这个过程当中浏览器什么都不会作直到DNS查找完毕。

缓存DNS查找能够改善页面性能。这种缓存须要一个特定的缓存服务器,这种服务器通常属于用户的ISP提供商或者本地局域网控制,可是它一样会在用户使用的计算机上产生缓存。DNS信息会保留在操做系统的DNS缓存中(微软Windows系统中DNS Client Service)。大多数浏览器有独立于操做系统之外的本身的缓存。因为浏览器有本身的缓存记录,所以在一次请求中它不会受到操做系统的影响。

Internet Explorer默认状况下对DNS查找记录的缓存时间为30分钟,它在注册表中的键值为DnsCacheTimeout。Firefox对DNS的查找记录缓存时间为1分钟,它在配置文件中的选项为network.dnsCacheExpiration(Fasterfox把这个选项改成了1小时)。

当客户端中的DNS缓存都为空时(浏览器和操做系统都为空),DNS查找的次数和页面中主机名的数量相同。这其中包括页面中URL、图片、脚本文件、样式表、Flash对象等包含的主机名。减小主机名的数量能够减小DNS查找次数。

减小主机名的数量还能够减小页面中并行下载的数量。减小DNS查找次数能够节省响应时间,可是减小并行下载却会增长响应时间。个人指导原则是把这些页面中的内容分割成至少两部分但不超过四部分。这种结果就是在减小DNS查找次数和保持较高程度并行下载二者之间的权衡了。

三、避免跳转

跳转是使用301和302代码实现的。下面是一个响应代码为301的HTTP头:

HTTP/1.1 301 Moved Permanently

Location:http://example.com/newuri

Content-Type: text/html

浏览器会把用户指向到Location中指定的URL。头文件中的全部信息在一次跳转中都是必需的,内容部分能够为空。无论他们的名称,301和302响应都不会被缓存除非增长一个额外的头选项,如Expires或者Cache-Control来指定它缓存。元素的刷新标签和JavaScript也能够实现URL的跳转,可是若是你必需要跳转的时候,最好的方法就是使用标准的3XXHTTP状态代码,这主要是为了确保“后退”按钮能够正确地使用。



可是要记住跳转会下降用户体验。在用户和HTML文档中间增长一个跳转,会拖延页面中全部元素的显示,由于在HTML文件被加载前任何文件(图像、Flash等)都不会被下载。

有一种常常被网页开发者忽略却每每十分浪费响应时间的跳转现象。这种现象发生在当URL本该有斜杠(/)却被忽略掉时。例如,当咱们要访问http://astrology.yahoo.com/astrology时,实际上返回的是一个包含301代码的跳转,它指向的是http://astrology.yahoo.com/astrology/(注意末尾的斜杠)。在Apache服务器中能够使用Alias 或者 mod\_rewrite或者the DirectorySlash来避免。

链接新网站和旧网站是跳转功能常常被用到的另外一种状况。这种状况下每每要链接网站的不一样内容而后根据用户的不一样类型(如浏览器类型、用户帐号所属类型)来进行跳转。使用跳转来实现两个网站的切换十分简单,须要的代码量也很少。尽管使用这种方法对于开发者来讲能够下降复杂程度,可是它一样下降用户体验。一个可替代方法就是若是二者在同一台服务器上时使用Alias和mod\_rewrite和实现。若是是由于域名的不一样而采用跳转,那么能够经过使用Alias或者mod\_rewirte创建CNAME(保存一个域名和另一个域名之间关系的DNS记录)来替代。

四、可缓存的AJAX

Ajax常常被说起的一个好处就是因为其从后台服务器传输信息的异步性而为用户带来的反馈的即时性。可是,使用Ajax并不能保证用户不会在等待异步的JavaScript和XML响应上花费时间。在不少应用中,用户是否须要等待响应取决于Ajax如何来使用。例如,在一个基于Web的Email客户端中,用户必须等待Ajax返回符合他们条件的邮件查询结果。记住一点,“异步”并不异味着“即时”,这很重要。

为了提升性能,优化Ajax响应是很重要的。提升Ajxa性能的措施中最重要的方法就是使响应具备可缓存性,具体的讨论能够查看Add an Expires or a Cache-Control Header。其它的几条规则也一样适用于Ajax:

Gizp压缩文件

减小DNS查找次数

精简JavaScript

避免跳转

配置ETags

让咱们来看一个例子:一个Web2.0的Email客户端会使用Ajax来自动完成对用户地址薄的下载。若是用户在上次使用过Email web应用程序后没有对地址薄做任何的修改,并且Ajax响应经过Expire或者Cacke-Control头来实现缓存,那么就能够直接从上一次的缓存中读取地址薄了。必须告知浏览器是使用缓存中的地址薄仍是发送一个新的请求。这能够经过为读取地址薄的Ajax URL增长一个含有上次编辑时间的时间戳来实现,例如,&t=11900241612等。若是地址薄在上次下载后没有被编辑过,时间戳就不变,则从浏览器的缓存中加载从而减小了一次HTTP请求过程。若是用户修改过地址薄,时间戳就会用来肯定新的URL和缓存响应并不匹配,浏览器就会重要请求更新地址薄。

即便你的Ajxa响应是动态生成的,哪怕它只适用于一个用户,那么它也应该被缓存起来。这样作能够使你的Web2.0应用程序更加快捷。

五、推迟加载内容

你能够仔细看一下你的网页,问问本身“哪些内容是页面呈现时所必需首先加载的?哪些内容和结构能够稍后再加载?

把整个过程按照onload事件分隔成两部分,JavaScript是一个理想的选择。例如,若是你有用于实现拖放和动画的JavaScript,那么它就以等待稍后加载,由于页面上的拖放元素是在初始化呈现以后才发生的。其它的例如隐藏部分的内容(用户操做以后才显现的内容)和处于折叠部分的图像也能够推迟加载

工具能够节省你的工做量:YUI Image Loader能够帮你推迟加载折叠部分的图片,YUI Get utility是包含JS和 CSS的便捷方法。好比你能够打开Firebug的Net选项卡看一下Yahoo的首页。

当性能目标和其它网站开发实践一致时就会相得益彰。这种状况下,经过程序提升网站性能的方法告诉咱们,在支持JavaScript的状况下,能够先去除用户体验,不过这要保证你的网站在没有JavaScript也能够正常运行。在肯定页面运行正常后,再加载脚原本实现如拖放和动画等更加花哨的效果。

六、预加载

预加载和后加载看起来彷佛偏偏相反,但实际上预加载是为了实现另一种目标。预加载是在浏览器空闲时请求未来可能会用到的页面内容(如图像、样式表和脚本)。使用这种方法,当用户要访问下一个页面时,页面中的内容大部分已经加载到缓存中了,所以能够大大改善访问速度。

下面提供了几种预加载方法:

无条件加载:触发onload事件时,直接加载额外的页面内容。以Google.com为例,你能够看一下它的spirit image图像是怎样在onload中加载的。这个spirit image图像在google.com主页中是不须要的,可是却能够在搜索结果页面中用到它。

有条件加载:根据用户的操做来有根据地判断用户下面可能去往的页面并相应的预加载页面内容。在search.yahoo.com中你能够看到如何在你输入内容时加载额外的页面内容。

有预期的加载:载入从新设计过的页面时使用预加载。这种状况常常出如今页面通过从新设计后用户抱怨“新的页面看起来很酷,可是却比之前慢”。问题可能出在用户对于你的旧站点创建了完整的缓存,而对于新站点却没有任何缓存内容。所以你能够在访问新站以前就加载一部内容来避免这种结果的出现。在你的旧站中利用浏览器的空余时间加载新站中用到的图像的和脚原本提升访问速度。

七、减小DOM元素数量

一个复杂的页面意味着须要下载更多数据,同时也意味着JavaScript遍历DOM的效率越慢。好比当你增长一个事件句柄时在500和5000个DOM元素中循环效果确定是不同的。

大量的DOM元素的存在乎味着页面中有能够不用移除内容只须要替换元素标签就能够精简的部分。你在页面布局中使用表格了吗?你有没有仅仅为了布局而引入更多的
元素呢?也许会存在一个适合或者在语意是更贴切的标签能够供你使用。

YUI CSS utilities能够给你的布局带来巨大帮助:grids.css能够帮你实现总体布局,font.css和reset.css能够帮助你移除浏览器默认格式。它提供了一个从新审视你页面中标签的机会,好比只有在语意上有意义时才使用
,而不是由于它具备换行效果才使用它。

DOM元素数量很容易计算出来,只须要在Firebug的控制台内输入:

document.getElementsByTagName('*').length

那么多少个DOM元素算是多呢?这能够对照有很好标记使用的相似页面。好比Yahoo!主页是一个内容很是多的页面,可是它只使用了700个元素(HTML标签)。

八、根据域名划分页面内容

把页面内容划分红若干部分能够使你最大限度地实现平行下载。因为DNS查找带来的影响你首先要确保你使用的域名数量在2个到4个之间。例如,你能够把用到的HTML内容和动态内容放在www.example.org上,而把页面各类组件(图片、脚本、CSS)分别存放在statics1.example.orgstatics.example.org上。

你可在Tenni Theurer和Patty Chi合写的文章Maximizing Parallel Downloads in the Carpool Lane找到更多相关信息。

九、使iframe的数量最小

ifrmae元素能够在父文档中插入一个新的HTML文档。了解iframe的工做理而后才能更加有效地使用它,这一点很重要。