前端面试梳理(一)

备战秋招,复习基础。若有错误,欢迎批评指正,共同进步!javascript

写在最前

整理自本身的面试经验+网络资料css

部分资料参考自网络,在具体内容前均有标出~感恩你们~html

因为篇幅缘由,拆成两篇~前端面试梳理(二)前端

电话面试

实话实说!保持自信!要有逻辑!vue

  • 自我介绍 3分钟做用,讲清重点经历。html5

    完结话术:...以上就是个人我的介绍。java

  • 简历相关 要熟!会检查真实性!node

  • 专业技术react

    是否具有专业技能jquery

    对工做的见解

    职业规划

    员工稳定性

  • 对公司的了解 尤为是对应岗位的业务。提早准备,列出可能的问题。

  • 兴趣爱好 尽可能与工做相关

  • 反问建议 下一步招聘流程

  • 感谢HR!!!

  • 话术:……回到您刚说的问题上

计算机基础

常见概念

JSON: 一种JS对象表示法的数据格式。能够表简单值(不支持Undefined)、对象(无序键值对)、数组(有序值列表)。不支持变量、函数或对象实例。

MIME:多用途互联网邮件扩展类型。

Fiber:一种编程思想。任务拆分和协同。当进程阻塞时,任务分割、异步调用、缓存策略

DN:域名,因特网上某一计算机组的名称。如 baidu.com

DNS:域名系统,将域名和IP一一映射

IP:互联网协议地址,是用户上网的数字标签

http:超文本传输协议

href:指定超连接目标的URL

URL:统一资源定位符。即网址http://www.baidu.com (服务器名 www)(网站名 www.baidu.com)

servlet:java提供的用于开发web服务器应用程序的一个组件。jsp是servlet的一种扩展。

cdn:内容分发网络。CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,经过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,下降网络拥塞,提升用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。

restful:URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操做。

1. 用名词定义接口名,用请求类型区分操做。
2. 用HTTP Status Code传递Server的状态信息。
复制代码

点击一个Url以后

1 DNS解析
2 http请求
3 TCP三次握手
4 数据传输
5 渲染文档
复制代码

url中的#和?

参考资料:URL 连接中 井号#、问号?、链接符& 分别有什么做用?

参考资料:VUE.js中访问地址的url带有#的问题

1 ?+任意参数 实现不一样参数值生成不一样页面或返回不一样结果 ?size=100
2 & 链接符,不一样参数的间隔符,通常与问号结合使用。?size=100&time=20171120
3 # Hash 表明网页中的一个位置。其右面的字符,就是该位置的标识符。#print
    为网页位置指定标识符,有两个方法。一是使用锚点,好比<a name="print"></a>,二是使用id属性,好比<div id="print" >
    HTTP请求不包括#。
    单单改变#后的部分,浏览器只会滚动到相应位置,不会从新加载网页。
    每一次改变#后的部分,都会在浏览器的访问历史中增长一个记录,使用"后退"按钮,就能够回到上一个位置。
    window.location.hash这个属性可读可写。读取时,能够用来判断网页状态是否改变;写入时,则会在不重载网页的前提下,创造一条访问历史记录。
    onhashchange事件,当#值发生变化时,就会触发这个事件。
4 vue中的#  VUE默认使用HASH模式
    HASH模式:
    HASH模式就是从访问地址动手脚,在访问地址的后面增长#而且带上须要的参数,这样后台就能对不一样的参数显示不一样的模块,并且 #以及后面的参数是不会被包含在HTTP请求中,所以对服务器的请求是没有影响的,更改参数也不会刷新页面。例子:网易云音乐的官网https://music.163.com/#
    history模式:
    history模式也是从访问地址动手脚,可是再也不使用#,而是想普通的访问地址那样使用/,但若是这样请求的话,服务器是须要另外配置才行,要否则容易出现404错误,具体怎么配置请自行百度。
复制代码

内存泄漏

1 意外的全局变量没法被回收
2 定时器未被正确关闭,致使使用的外部变量没法被释放
3 事件监听未正确被销毁
4 闭包,会致使父级中变量没法被释放
5 dom引用,dom元素被删除时,内存中的引用未被正确清空
可用chrome中的timeline来进行内存标记~
复制代码

解决闭包的内存泄露

window.onload = function(){
    var el = document.getElementById("id");
    var id = el.id; //解除循环引用
    el.onclick = function(){
        alert(id); 
    }
    el = null; // 将闭包引用的外部函数中活动对象清除
}
复制代码

Http1.0 1.1 2.0的区别

资料参考:HTTP1.0、HTTP1.1 和 HTTP2.0 的区别

资料参考:如何优雅的谈论HTTP/1.0/1.1/2.0

HTTP1.1是当前使用最为普遍的HTTP协议

  • HTTP1.0和HTTP1.1相比

    缓存处理:在HTTP1.0中主要使用header里的If-Modified-Since,Expires来作为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

    带宽优化及网络链接的使用:HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是须要某个对象的一部分,而服务器却将整个对象送过来了,而且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它容许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和链接。

    错误通知的管理:在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

    Host头处理:在HTTP1.0中认为每台服务器都绑定一个惟一的IP地址,所以,请求消息中的URL并无传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上能够存在多个虚拟主机(Multi-homed Web Servers),而且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中若是没有Host头域会报告一个错误(400 Bad Request)。

    长链接:HTTP 1.1支持长链接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP链接上能够传送多个HTTP请求和响应,减小了创建和关闭链接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,必定程度上弥补了HTTP1.0每次请求都要建立链接的缺点。 经过设置http的请求头部和应答头部,保证本次数据请求结束以后,下一次请求仍能够重用这一通道,避免从新握手。

  • HTTP2.0和HTTP1.X相比

    新的二进制格式(Binary Format):HTTP1.x的解析是基于文本。基于文本协议的格式解析存在自然缺陷,文本的表现形式有多样性,要作到健壮性考虑的场景必然不少,二进制则不一样,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

    多路复用(MultiPlexing):即链接共享,即每个request都是是用做链接共享机制的。一个request对应一个id,这样一个链接上能够有多个request,每一个链接的request能够随机的混杂在一块儿,接收方能够根据request的 id将request再归属到各自不一样的服务端请求里面。

    header压缩:如上文中所言,对前面提到过HTTP1.x的header带有大量信息,并且每次都要重复发送,HTTP2.0使用了专门为首部压缩而设计的 HPACK 算法,使用encoder来减小须要传输的header大小,通信双方各自cache一份header fields表,既避免了重复header的传输,又减少了须要传输的大小。

    服务端推送(server push):服务端推送能把客户端所须要的资源伴随着index.html一块儿发送到客户端,省去了客户端重复请求的步骤。正由于没有发起请求,创建链接等操做,因此静态资源经过服务端推送的方式能够极大地提高速度。例如个人网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就能够直接从缓存中获取到,不用再发请求了。

  • HTTPS与HTTP相比

    HTTPS协议须要到CA申请证书,通常免费证书不多,须要交费。

    HTTP协议运行在TCP之上,全部传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,全部传输的内容都通过加密的。

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

    HTTPS能够有效的防止运营商劫持,解决了防劫持的一个大问题。

  • HTTS

    HTTPS在传输数据以前须要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程当中将确立双方加密传输数据的密码信息。TLS/SSL协议不只仅是一套加密传输的协议,TLS/SSL中使用了非对称加密,对称加密以及HASH算法。

    握手过程的简单描述以下:

    1.浏览器将本身支持的一套加密规则发送给网站。
      2.网站从中选出一组加密算法与HASH算法,并将本身的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
      3.得到网站证书以后浏览器要作如下工做:
          a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),若是证书受信任,则浏览器栏里面会显示一个小锁头,不然会给出证书不受信的提示。
          b) 若是证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
          c) 使用约定好的HASH计算握手消息,并使用生成的随机数对消息进行加密,最后将以前生成的全部信息发送给网站。
      4.网站接收浏览器发来的数据以后要作如下的操做:
          a) 使用本身的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。
          b) 使用密码加密一段握手消息,发送给浏览器。
      5.浏览器解密并计算握手消息的HASH,若是与服务端发来的HASH一致,此时握手过程结束,以后全部的通讯数据将由以前浏览器生成的随机密码并利用对称加密算法进行加密。
    复制代码

    这里浏览器与网站互相发送加密的握手消息并验证,目的是为了保证双方都得到了一致的密码,而且能够正常的加密解密数据。其中非对称加密算法用于在握手过程当中加密生成的密码,对称加密算法用于对真正传输的数据进行加密,而HASH算法用于验证数据的完整性。因为浏览器生成的密码是整个数据加密的关键,所以在传输的时候使用了非对称加密算法对其加密。非对称加密算法会生成公钥和私钥,公钥只能用于加密数据,所以能够随意传输,而网站的私钥用于对数据进行解密,因此网站都会很是当心的保管本身的私钥,防止泄漏。 TLS握手过程当中若是有任何错误,都会使加密链接断开,从而阻止了隐私信息的传输。正是因为HTTPS很是的安全,攻击者没法从中找到下手的地方,因而更多的是采用了假证书的手法来欺骗客户端,从而获取明文的信息。

http请求

  • 请求报文
    • 请求行:请求方法字段、URL字段和HTTP协议版本 例如:GET /index.html HTTP/1.1
    • 请求头:key value形式,如User-Agent:产生请求的浏览器类型; Accept:客户端可识别的内容类型列表;Host:主机地址
    • 请求数据:post方法中,会把数据以key value形式发送请求
    • 空行:发送回车符和换行符,通知服务器如下再也不有请求头
  • 响应报文
    • 状态行:http版本+状态码+状态代码的文本描述 例如:HTTP/1.1 200 ok
    • 消息报头:包含服务器类型,日期,长度,内容类型等
    • 响应正文:服务器返回的HTML页面或者json数据

HTTP缓存机制基原理

资料参考:完全弄懂HTTP缓存机制及原理

web缓存三类:服务器端缓存、浏览器端缓存、数据库数据缓存

  • 强制缓存:在缓存数据未失效的状况下,能够直接使用缓存数据。浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)。

  • 对比缓存:浏览器第一次请求数据时,服务器会将缓存标识与数据一块儿返回给客户端,客户端将两者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,能够使用缓存数据。

资料参考:HTTP缓存控制小结

优先级从高到低分别是 Pragma -> Cache-Control -> Expires

1.Pragma:禁用缓存。 当该字段值为no-cache的时候(事实上如今RFC中也仅标明该可选值),会知会客户端不要对该资源读缓存,即每次都得向服务器发一次请求才行。

2.Expires: 启用缓存和定义缓存时间。Expires的值对应一个GMT(格林尼治时间),好比Mon, 22 Jul 2002 11:12:01 GMT来告诉浏览器资源缓存过时时间,若是还没过该时间点则不发请求。

3.Cache-Control:定义缓存过时时间,实现缓存文件是否更新的验证、提高缓存的复用率

1. Last-Modified

    ⑴ If-Modified-Since: Last-Modified-value
    示例为 If-Modified-Since: Thu, 31 Mar 2016 07:07:52 GMT
    该请求首部告诉服务器若是客户端传来的最后修改时间与服务器上的一致,则直接回送304 和响应报头便可。
    当前各浏览器均是使用的该请求首部来向服务器传递保存的 Last-Modified 值。

    ⑵ If-Unmodified-Since: Last-Modified-value
    该值告诉服务器,若Last-Modified没有匹配上(资源在服务端的最后更新时间改变了),则应当返回412(Precondition Failed) 状态码给客户端。 Last-Modified 存在必定问题,若是在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会由于Last-Modified时间匹配不上而返回了整个实体给客户端(即便客户端缓存里有个如出一辙的资源)。
    
2. ETag:经过某种算法,给资源计算得出一个惟一标志符(好比md5标志),在把资源响应给客户端的时候,会在实体首部加上“ETag: 惟一标识符”一块儿返回给客户端。

    ⑴ If-None-Match: ETag-value
    示例为 If-None-Match: "5d8c72a5edda8d6a:3239" 告诉服务端若是 ETag 没匹配上须要重发资源数据,不然直接回送304 和响应报头便可。 当前各浏览器均是使用的该请求首部来向服务器传递保存的 ETag 值。

    ⑵ If-Match: ETag-value
    告诉服务器若是没有匹配到ETag,或者收到了“*”值而当前并无该资源实体,则应当返回412(Precondition Failed) 状态码给客户端。不然服务器直接忽略该字段。
    须要注意的是,若是资源是走分布式服务器(好比CDN)存储的状况,须要这些服务器上计算ETag惟一值的算法保持一致,才不会致使明明同一个文件,在服务器A和服务器B上生成的ETag却不同。
复制代码

服务器再次请求流程

用户请求匹配规则(nginx相关)

资料参考:Nginx Location指令URI匹配规则详解

当nginx收到一个请求后,会截取请求的URI部份,去搜索全部location指令中定义的URI匹配模式。在server模块中能够定义多个location指令来匹配不一样的url请求,多个不一样location配置的URI匹配模式,整体的匹配原则是:先匹配普通字符串模式,再匹配正则模式。

只识别URI部份,例如请求为:/test/abc/user.do?name=xxxx 
复制代码
  • Nginx匹配请求的流程:

    1. 先查找是否有=开头的精确匹配,如:location = /test/abc/user.do { … }

    2. 再查找普通匹配,以 最大前缀 为原则,若有如下两个location,则会匹配后一项

      • location /test/ { … }
      • location /test/abc { … }
    3. 匹配到一个普通格式后,搜索并未结束,而是暂存当前匹配的结果,并继续搜索正则匹配模式

    4. 全部正则匹配模式location中找到第一个匹配项后,就以此项为最终匹配结果。因此正则匹配项匹配规则,受定义的先后顺序影响,但普通匹配模式不会

    5. 若是未找到正则匹配项,则以3中缓存的结果为最终匹配结果

    6. 若是一个匹配都没搜索到,则返回404

负载均衡和容错方式

参考资料:服务器负载均衡的基本功能和实现原理

负责均衡服务器根据负载均衡算法来分发请求到不一样的主服务器。

每一个主服务器都是等价的,均可以完成相同的功能。

通常来讲负载均衡设备都会默认支持多种负载均衡分发策略,例如:

轮询(RoundRobin)将请求顺序循环地发到每一个服务器。当其中某个服务器发生故障,AX就把其从顺序循环队列中拿出,不参加下一次的轮询,直到其恢复正常。

比率(Ratio):给每一个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每一个服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

优先权(Priority):给全部服务器分组,给每一个组定义优先权,将用户的请求分配给优先级最高的服务器组(在同一组内,采用预先设定的轮询或比率算法,分配用户的请求);当最高优先级中全部服务器或者指定数量的服务器出现故障,AX将把请求送给次优先级的服务器组。这种方式,实际为用户提供一种热备份的方式。

最少链接数(LeastConnection):AX会记录当前每台服务器或者服务端口上的链接数,新的链接将传递给链接数最少的服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常

最快响应时间(Fast Reponse time):新的链接传递给那些响应最快的服务器。当其中某个服务器发生故障,AX就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

哈希算法( hash):  将客户端的源地址,端口进行哈希运算,根据运算的结果转发给一台服务器进行处理,当其中某个服务器发生故障,就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。

基于策略的负载均衡:针对不一样的数据流设置导向规则,用户可自行编辑流量分配策略,利用这些策略对经过的数据流实施导向控制。

基于数据包的内容分发:例如判断HTTP的URL,若是URL中带有.jpg的扩展名,就把数据包转发到指定的服务器。
复制代码

容错(fall-over):容错是负载均衡服务器里面的一个概念。是指当一台主服务器宕机后,集群可以继续提供服务的策略。好比说当主服务器A宕机后,负载均衡服务器要能发现主服务器A不能继续提供服务了,之前分发到主服务器A的请求要分发到其它主服务器。这种处理就是容错处理。

面向对象

参考资料:面向对象(一)|面向对象概念及优势

面向对象三大特性:封装、继承、多态。

面向对象的好处:

  1. 将对象进行分类,分别封装它们的数据和能够调用的方法,方便了函数、变量、数据的管理,方便方法的调用(减小重复参数等),尤为是在编写大型程序时更有帮助。
  2. 用面向对象的编程能够把变量当成对象进行操做,让编程思路更加清晰简洁,并且减小了不少冗余变量的出现

方法重写和重载

方法重写(overriding):

也叫子类的方法覆盖父类的方法,要求返回值、方法名和参数都相同。
子类抛出的异常不能超过父类相应方法抛出的异常。(子类异常不能超出父类异常)
子类方法的的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)。
复制代码

方法重载(overloading):

重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,可是参数却不相同,方法体也不相同,最多见的重载的例子就是类的构造函数。
复制代码

java后端如何存取图片文件

资料参考:java后台接受到图片后保存方法

前端代码:

<form enctype="multipart/form-data" method="post" action="/testUploadimg"> 
    图片:<input type="file" name="file" /><br/> 
    <input type="submit" value="上传" />.
</form>
复制代码

后端代码:

//调整页面请求

@Controllerpublic class UploadController {  
//跳转到上传文件的页面  
@RequestMapping(value = "/gouploadimg", method = RequestMethod.GET)  
    public String goUploadImg() {    
    //跳转到 templates 目录下的 uploadimg.html    
    return "uploadimg";  
}  
 
//处理文件上传  
@ResponseBody //返回json数据  
@RequestMapping(value = "/testUploadimg", method = RequestMethod.POST)  
 
//上传请求方法
public String uploadImg(@RequestParam("file") MultipartFile file, HttpServletRequest request) {    
    tring contentType = file.getContentType();    
    String fileName = file.getOriginalFilename();    
    String filePath = "D:/img";    
    if (file.isEmpty()) {      
        return "文件为空!";    
    }    
    try {      
        uploadFile(file.getBytes(), filePath, fileName);    
    } catch (Exception e) {      
        // TODO: handle exception    
    }    
    //返回json    
    return "上传成功";  
}  

//存储图片方法
public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {    
    File targetFile = new File(filePath);    
    if (!targetFile.exists()) {      
        targetFile.mkdirs();    
    }    
    FileOutputStream out = new FileOutputStream(filePath +"/"+ fileName);    
    out.write(file);    
    out.flush();    
    out.close();  
    }
}
复制代码

如何鉴权

资料参考:先后端常见的几种鉴权方式

经常使用的鉴权有四种:

  1. HTTP Basic Authentication
  2. session-cookie
  3. Token 验证
  4. OAuth(开放受权)
  • HTTP Basic Authentication:HTTP服务器对客户端进行用户身份证的方法

    1. 客户端向服务器请求数据,请求的内容多是一个网页或者是一个ajax异步请求,此时,假设客户端还没有被验证,则客户端提供以下请求至服务器:Get /index.html HTTP/1.0; Host:www.google.com
    2. 服务器向客户端发送验证请求代码401,(WWW-Authenticate: Basic realm=”google.com”这句话是关键,若是没有客户端不会弹出用户名和密码输入界面)
    3. 当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登陆窗口,要求用户输入用户名和密码。
    4. 用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成以下内容:Get /index.html HTTP/1.0; Host:www.google.com;Authorization: Basic d2FuZzp3YW5n → 用户名:密码 经过base64加密,是浏览器默认的行为,不须要人为加密
    5. 服务器收到上述请求信息后,将Authorization字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端

    缺陷:加密方式简单,是base64加密是可逆的。同时在每一个请求的头上都会附带上用户名和密码信息,这样在外网是很容易被嗅探器探测到的。

  • session-cookie:利用服务器端的session(会话)和浏览器端的cookie来实现先后端的认证。在服务器端建立一个会话(seesion),将同一个客户端的请求都维护在各自的会话中,每当请求到达服务器端的时候,先去查一下该客户端有没有在服务器端建立seesion,若是有则已经认证成功了,不然就没有认证。

    1. 服务器在接受客户端首次访问时在服务器端建立seesion,而后保存seesion(咱们能够将seesion保存在内存中,也能够保存在redis中,推荐使用后者),而后给这个session生成一个惟一的标识字符串,而后在响应头中种下这个惟一标识字符串。
    2. 签名。这一步只是对sid进行加密处理,服务端会根据这个secret密钥进行解密。(非必需步骤)
    3. 浏览器中收到请求响应的时候会解析响应头,而后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息。
    4. 服务器在接受客户端请求时会去解析请求头cookie中的sid,而后根据这个sid去找服务器端保存的该客户端的session,而后判断该请求是否合法。
  • Token 验证:客户端在首次登录之后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就好了,服务器端会拦截全部的请求,而后校验token的合法性,合法就放行,不合法就返回401(鉴权失败)

    1. 客户端使用用户名跟密码请求登陆
    2. 服务端收到请求,去验证用户名与密码
    3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
    4. 客户端收到 Token 之后能够把它存储起来,好比放在 Cookie 里或者 Local Storage 里
    5. 客户端每次向服务端请求资源的时候须要带着服务端签发的 Token
    6. 服务端收到请求,而后去验证客户端请求里面带着的Token,若是验证成功,就向客户端返回请求的数据
  • OAuth(开放受权):容许用户受权第三方网站访问他们存储在另外的服务提供者上的信息,而不须要将用户名和密码提供给第三方网站或分享他们数据的全部内容。为了保护用户数据的安全和隐私,第三方网站访问用户数据前都须要显式的向用户征求受权。咱们常见的提供OAuth认证服务的厂商有支付宝,QQ,微信。

    1. 向用户请求受权,如今不少的网站在登录的时候都有第三方登录的入口,当咱们点击等第三方入口时,第三方受权服务会引导咱们进入第三方登录受权页面。
    2. 返回用户凭证(code),并返回一个凭证(code),当用户点击受权并登录后,受权服务器将生成一个用户凭证(code)。这个用户凭证会附加在重定向的地址redirect_uri的后面
    3. 第三方应用后台经过第二步的凭证(code)向受权服务器请求Access Token
    4. 受权服务器赞成受权后,返回一个资源访问的凭证(Access Token)
    5. 第三方应用经过第四步的凭证(Access Token)向资源服务器请求相关资源
    6. 资源服务器验证凭证(Access Token)经过后,将第三方应用请求的资源返回

cookie session localStorage sessionStorage

cookie:客户端保存状态的一种方案。
    服务器在Http响应的头中加入一行特殊的指令用以在客户端生成相应的cookie。
    保存在内存里,不超过4K
    cookie = new Cookie("username","aaa");
    cookie.setMaxAge(0);
    response.addCookie(cookie);
session:在服务端实现。
    检查客户端请求中的sessionID,检索或建立
    服务端会设置一个响应头Set-Cookie,返回给客户端,例如:Set-Cookie:SESSIONID=12345678;客户端接收到这个响应后,此后发送的每个请求浏览器都会自动带上Cookie请求头,对应内容是Cookie:SESSIONID=12345678。在服务端内存中存有session,将客户端发送的请求中的cookie值与内存中的session进行对比,就能够识别这个客户端了。
    session有一个缺陷:若是web服务器作了负载均衡,那么下一个操做请求到了另外一台服务器的时候session会丢失。
复制代码

! 重要信息放在session中,其余保留信息放在cookie中!

session token

token的意思是“令牌”,是用户身份的验证方式,最简单的token组成:uid(用户惟一的身份标识)、time(当前时间的时间戳)、sign(签名,由token的前几位+盐以哈希算法压缩成必定长的十六进制字符串,能够防止恶意第三方拼接token请求服务器)。还能够把不变的参数也放进token,避免屡次查库

session 和 oauth token并不矛盾,做为身份认证token安全性比session好,由于每一个请求都有签名还能防止监听以及重放攻击,而session就必须靠链路层来保障通信安全了。

Session 是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。所谓Session 认证只是简单的把User 信息存储到Session 里,由于SID 的不可预测性,暂且认为是安全的。这是一种认证手段。 而Token ,若是指的是OAuth Token 或相似的机制的话,提供的是 认证 和 受权 ,认证是针对用户,受权是针对App 。其目的是让 某App有权利访问 某用户 的信息。这里的 Token是惟一的。不能够转移到其它 App上,也不能够转到其它 用户 上。 转过来讲Session 。Session只提供一种简单的认证,即有此 SID,即认为有此 User的所有权利。是须要严格保密的,这个数据应该只保存在站方,不该该共享给其它网站或者第三方App。 因此简单来讲,若是你的用户数据可能须要和第三方共享,或者容许第三方调用 API 接口,用 Token 。若是永远只是本身的网站,本身的 App,用什么就无所谓了。

token就是令牌,好比你受权(登陆)一个程序时,他就是个依据,判断你是否已经受权该软件;cookie就是写在客户端的一个txt文件,里面包括你登陆信息之类的,这样你下次在登陆某个网站,就会自动调用cookie自动登陆用户名;session和cookie差很少,只是session是写在服务器端的文件,也须要在客户端写入cookie文件,可是文件里是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

localStorage设置过时时间

参考资料:localStorage设置过时时间实例

localStorage的数据若是不进行手动删除或者删除缓存的话,是永久保存的。

给一个过时的时间,放在第二个参数中。在调用数据的时候,判断当前时间是否大于设置的过时时间,若是是,就将数据删除,作一个相应提示或操做便可。

let setTime = new Date().getTime() + (1000 * 60);    // 测试,设置1分钟后数据过时
 
localStorage.setItem('test', JSON.stringify({
    data: 'data1',
    expiration: setTime
}));
 
 
let data = localStorage.test;
data = JSON.parse(data)
 
let time = data.expiration;
let value = data.data;
 
if(new Date().getTime() > time) {
    delete localStorage.test;
    // 这里开始执行超时的代码
}
else {
    // 这里开始执行未超时的代码
}
复制代码

OSI七层网络模型

资料参考:一张很是强大的OSI七层模型图解

OSI

TCP/IP

资料参考:关于TCP/IP,必须知道的十个知识点

待补充!!

线程和进程

根本区别:进程是操做系统资源分配的基本单位,而线程是任务调度和执行的基本单位。

在开销方面:每一个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程能够看作轻量级的进程,同一类线程共享代码和数据空间,每一个线程都有本身独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操做系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(经过CPU调度,在每一个时间片中只有一个线程执行)。

内存分配方面:系统在运行的时候会为每一个进程分配不一样的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

包含关系:没有线程的进程能够看作是单线程的,若是一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,因此线程也被称为轻权进程或者轻量级进程。
复制代码

浏览器三线程:

js引擎线程:是基于事件驱动的单线程
GUI渲染线程:负责渲染浏览器界面,与Js互斥
浏览器事件触发线程:把待处理的任务放到任务队列中,等js主线程空闲再处理
复制代码

攻击

XSS攻击:

着重:注入代码实现
表现:跨站脚本攻击,容许用户将代码植入,提供给其余用户使用的页面,如html代码和客户端脚本。
防范:设置httpOnly,禁止用document.cookie操做;输入检查:在用户输入的时候进行格式检查;对输出转义。
复制代码

CSRF攻击:

着重:攻击效果
表现:跨站点请求伪造,欺骗用户的浏览器,发送http请求给目标站点。
防御:1 设置白名单;
      2 限制不被第三方网站请求;
      3 检查 Referer字段:这个字段用以标明请求来源于哪一个地址。在处理敏感数据请求时,一般来讲,Referer 字段应和请求的地址位于同一域名下;
      4 添加校验 Token:这种数据一般是表单中的一个数据项。服务器生成token并附加在表单中,其内容是一个伪乱数。当客户端经过表单提交请求时,这个伪乱数也一并提交上去以供校验。正常的访问时,客户端浏览器可以正确获得并传回这个伪乱数,而经过 CSRF 传来的欺骗性攻击中,攻击者无从事先得知这个伪乱数的值,服务器端就会由于校验 Token 的值为空或者错误,拒绝这个可疑请求。
      5 经过输入验证码来校验合法请求。
复制代码

sql注入攻击:

攻击方式:服务器上的数据库运行非法的 SQL语句,主要经过拼接字符串的形式来完成,改变sql语句自己的语义。经过sql语句实现无帐号登录,甚至篡改数据库。
防护:1 使用参数化查询:使用预编译语句,预先编译的SQL语句,而且传入适当参数屡次执行。因为没有拼接的过程,所以能够防止 SQL注入的发生。使用preparedStatement的参数化sql,经过先肯定语义,再传入参数,就不会由于传入的参数改变sql的语义。(经过setInt,setString,setBoolean传入参数)
      2 单引号转换:将传入的参数中的单引号转换为连续两个单引号,PHP 中的 Magic quote 能够完成这个功能。
      3 检查变量数据类型和格式。
      4 使用正则表达式过滤传入的参数,对特殊符号过滤或者转义处理。
复制代码

扫描二维码登入PC的工做原理

1 pc端随机生成一个含有惟一uid的二维码,并与服务器创建一个长链接;
2 手机扫描二维码,解析出二维码中的uid,并把这个uid和手机端的用户密码进行绑定,上传给服务器;
3 服务器得到客户端信息以后,pc端的长链接轮询操做会得到该消息,显示该帐号的信息;
4 pc端会再开一个长链接与手机端保持通讯,等待手机端确认登录后,得到服务器受权的token,就能够在pc端登录进行正常通讯了。
复制代码

前端基础

ajax

概念

向服务器请求额外的数据而无需卸载页面

HTTP头部信息:服务器接收头部信息,决定后续操做。

header:服务器以HTTP协议传HTML资料到浏览器前所送出的字符串。`协议头字段名:内容`
复制代码

get和post区别

参考资料:HTTP 方法:GET 对比 POST

  • 简单区别
比较 GET POST
后退按钮/刷新 无害 数据会被从新提交(浏览器应该告知用户数据会被从新提交)。
书签 可收藏为书签 不可收藏为书签
缓存 能被缓存 不能缓存
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。
历史 参数保留在浏览器历史中。 参数不会保存在浏览器历史中。
对数据长度的限制 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 无限制。
对数据类型的限制 只容许 ASCII 字符。 没有限制。也容许二进制数据。
安全性 与 POST 相比,GET 的安全性较差,由于所发送的数据是 URL 的一部分。在发送密码或其余敏感信息时毫不要使用 GET ! POST 比 GET 更安全,由于参数不会被保存在浏览器历史或 web 服务器日志中。
可见性 数据在 URL 中对全部人都是可见的。 数据不会显示在 URL 中。
  • 数据请求过程

    • GET请求(2次交互):用于向服务器查询某些信息

    浏览器请求tcp链接(第一次握手) 服务器答应进行tcp链接(第二次握手) 浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,因此http会在此时进行第一次数据发送) 服务器返回200 ok响应。

    • POST请求(3次交互):用于向服务器发送应该被保存的数据。post消耗的资源更多。传送的数据相同,get的速度最可能是post的两倍。

    浏览器请求tcp链接(第一次握手) 服务器答应进行tcp链接(第二次握手) 浏览器确认,并发送post请求头(第三次握手,这个报文比较小,因此http会在此时进行第一次数据发送) 服务器返回100 continue响应 浏览器开始发送数据 服务器返回200 ok响应

FormData类型:序列化表单,建立与表格格式相同的数据

超时设定:timeout属性;调用ontimeout事件处理程序

原生js实现

核心:XMLHttpRequest对象。使用XHR对象取得新数据,再经过DOM将新数据插入页面中。与数据格式无关。
复制代码

建立XHR对象:

var xhr = creatXHR();
//检测状态
xhr.onreadystatechange = function(){
    if (xhr.readyState == 4){
        if (( xhr.status >=200 && xhr.status <300 ) || xhr.status == 304 ){
            alert(xhr.responseText);
        }else{
            alert("Request was unsuccessful:" + xhr.statusText);
        }
    }
};
//启动一个请求以备发送
xhr.open("get","example.txt",true);← 是否异步
//发送请求,无数据则必须有null
xhr.send(null);
复制代码
readyState 状态
0 未open
1 已open未send
2 已send未回应
3 已响应部分
4 已所有响应

react实现

axios:

axios.get(this.props.url).then(function(response){
        // 在这儿实现 setState
    }).catch(function(error){
        // 处理请求出错的状况
    });
复制代码

reqwest:

reqwest({
    url: 'path/to/data.jsonp?foo=bar'
  , type: 'jsonp'
  , jsonpCallback: 'foo'
})
  .then(function (resp) {
    qwery('#content').html(resp.content)
  }, function (err, msg) {
    qwery('#errors').html(msg)
  })
  .always(function (resp) {
    qwery('#hide-this').hide()
  })
复制代码

vue实现

基础笔记梳理 - Vue

axios({
    method:'post',
    url:'/user',
    data:{
        firstName:'a',
        lastName:'b'
    }
});
复制代码

跨域

同源政策(为何AJAX不能跨域请求)

同源政策:不是同协议/同域名/同端口的网页没法相互访问
策略本质:一个域名的Js在未经容许的状况下,不得读取另外一个域名的内容。但浏览器并不阻止你向另外一个域名发送请求。
复制代码

CORS

参考资料:跨域CORS原理及调用具体示例 太难了,弄不懂!

使用自定义的HTTP头部让浏览器与服务器进行沟通。决定请求或相应是否成功。

XDR类型:X Domain Request类型 只支持get和post

建立XDR实例(异步执行):调用open(请求类型,url),再调用send()

使用:只须要向响应头header中注入Access-Control-Allow-Origin,这样浏览器检测到header中的Access-Control-Allow-Origin,则就能够跨域操做了。

实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。

  • 简单请求:post get head

    • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
    • 浏览器 在头信息之中,添加一个Origin字段,说明本次请求来自哪一个源(协议 + 域名 + 端口)
    GET /cors HTTP/1.1
    Origin: http://api.bob.com
    Host: api.alice.com
    Accept-Language: en-US
    Connection: keep-alive
    User-Agent: Mozilla/5.0...
    复制代码
    • 服务器 若是Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
    Access-Control-Allow-Origin: http://api.bob.com   → 必含,值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
    Access-Control-Allow-Credentials: true  →可选。值是一个布尔值,表示是否容许发送Cookie。默认状况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie能够包含在请求中,一块儿发给服务器。这个值也只能设为true,若是服务器不要浏览器发送Cookie,删除该字段便可。
    Access-Control-Expose-Headers: FooBar → 可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其余字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')能够返回FooBar字段的值。
    Content-Type: text/html; charset=utf-8
    复制代码
  • 非简单请求 PUT DELETE,或者Content-Type:application/json。

    • 在正式通讯以前,增长一次HTTP查询请求,称为"预检"请求(preflight)。先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及能够使用哪些HTTP动词和头信息字段。只有获得确定答复,浏览器才会发出正式的XMLHttpRequest请求,不然就报错。
    浏览器发送请求:
    var url = 'http://api.alice.com/cors';
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', url, true);
    xhr.setRequestHeader('X-Custom-Header', 'value');
    xhr.send();
    
    先预检:
    OPTIONS /cors HTTP/1.1
    Origin: http://api.bob.com
    Access-Control-Request-Method: PUT  → 必须,列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
    Access-Control-Request-Headers: X-Custom-Header  → 逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
    Host: api.alice.com
    Accept-Language: en-US
    Connection: keep-alive
    User-Agent: Mozilla/5.0...
    复制代码
    • 服务器确认容许跨源请求,作出回应
    Access-Control-Allow-Methods: GET, POST, PUT
    Access-Control-Allow-Headers: X-Custom-Header → 若是浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,代表服务器支持的全部头信息字段,不限于浏览器在"预检"中请求的字段。
    Access-Control-Allow-Credentials: true → 
    Access-Control-Max-Age: 1728000 → 可选,用来指定本次预检请求的有效期,单位为秒
    复制代码
    • 服务器端代码
    response.setHeader("Access-Control-Allow-Origin", "*");  
    复制代码

图像ping

JSONP

原理:经过script标签来引入一个js文件,这个js文件载入成功后会执行咱们在url参数中指定的函数,而且把咱们须要的json数据做为参数传入。可是jsonp这种方式是须要服务端对应页面进行相应配合的。
复制代码

修改document.domain

适用:浏览器中不一样域的框架之间是不能进行js交互的例如:www.example.com/a.html和example.com/b.html这两个页面的document.domain都设成相同的域名就能够了。但要注意的是,document.domain的设置是有限制的,咱们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

例如:a.b.example.com 中某个文档的document.domain能够设成a.b.example.com、b.example.com、example.com中的任意一个,可是不能够设成c.a.b.example.com,由于这是当前域的子域,也不能够设成baidu.com,由于主域已经不相同了。

注意:修改document.domain的方法只适用于不一样子域的框架间的交互。若是你想经过ajax的方法去与不一样子域的页面交互,除了使用jsonp的方法外,还能够用一个隐藏的iframe来作一个代理。原理就是让这个iframe载入一个与你想要经过ajax获取数据的目标页面处在相同的域的页面,因此这个iframe中的页面是能够正常使用ajax去获取你要的数据的,而后就是经过咱们刚刚讲得修改document.domain的方法,让咱们能经过js彻底控制这个iframe,这样咱们就可让iframe去发送ajax请求,而后收到的数据咱们也能够得到了。
复制代码

window.name

对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。注意:window.name的值只能是字符串的形式,这个字符串的大小最大能容许2M左右甚至更大的一个容量,具体取决于不一样的浏览器,但通常是够用了。

原理:在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,而后a.html再去获得iframe获取到的数据。
复制代码

HTML5中新引入的window.postMessage()方法

原理:window.postMessage(message,targetOrigin)方法是html5新引进的特性,能够使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。参数:第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,若是不想限定域,能够使用通配符 * 接收:要接收消息的window对象,但是经过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。适用:一个页面有几个框架的那种状况,由于每个框架都有一个window对象。在讨论第二种方法的时候,咱们说过,不一样域的框架间是能够获取到对方的window对象的,并且也能够使用window.postMessage这个方法
复制代码

Comet 服务器推送

一种更高级的ajax技术,让服务器几乎可以实时地向客户端推送数据。

实现方式:长轮询、流

短轮询:浏览器   —请求→  服务器  —响应→  浏览器

长轮询:浏览器   —请求→  服务器  —(有数据可发送时)响应→  浏览器

HTTP流:浏览器   —请求→  服务器(保持连接打开)   —周期性发送数据→  浏览器
复制代码

web sockets

在一个单独的持久连接上实现双向通讯。与服务器进行全双工、双向通讯的信道。使用自定义的协议而非HTTP,专门为快速传输小数据设计。

通信相关

前端领域的通信

前端和后端、前端和移动端、前端页面和iframe、浏览器各tab之间、web worker线程通讯、路由间通讯、父子组件通讯
复制代码

通信的要点和目的

要点:发送者和接收者 / 传输媒介 / 数据 / 格式协议
目的:同步数据 / 传递指令
复制代码

重定向和转发

浏览器发送请求,服务器发送特定响应,实现重定向。浏览器收到响应后,根据状态码判断重定向,并使用指定新URL从新请求。

转发:服务器端。TBC。。。

状态码

状态码 含义
1xx 接受,继续处理
200 成功,并返回数据
201 已建立
202 已接受
203 成功,但未受权
204 成功,但无内容
205 成功,且重置内容
206 成功,部份内容
301 永久移动,需重定向
302 临时移动,可以使用URI
304 资源未修改,可以使用缓存
305 需使用代理访问
400 请求语法错误
401 须要身份认证
403 拒绝请求
404 资源不存在
500 服务器错误

渲染相关

Reflow和Repaint

应尽可能规避!

repaint:重绘。一部分重画,不影响总体布局。如颜色改变。
    例如:visibility:hidden
    监控:使用开发者工具能够监控页面重绘
    
reflow:回流。元素几何尺寸改变,须要从新验证并计算渲染树。
    例如:display:none
    致使reflow的操做:
        1. 调整窗口大小
        2. 改变字体(若用rem设置根目录字体大小,则不回流)
        3. 增长或移除样式表
        4. 内容变化 Input
        5. 激活css伪类
        6. 操做class属性
        7. 基本操做dom
        8. 计算 offsetWidth / offsetHeight 获取位置
        9. 在html中直接设置style(会下降代码利用率,影响性能)
    减小reflow的操做:
        1. 动画效果position:absolute/fixed 使元素脱离文档流
        2. 避免使用table
        3. 避免多项内联样式
        4. 尽量在元素末端改变class
        5. 精简dom层级
        6. 使用display:none在隐藏期间配置可能致使屡次reflow的样式,配置完成后再转为可见
        7. 屡次元素css属性操做写到同一个class里
        8. 避免在Js循环里操做dom
        9. 预置css元素的大小
复制代码

高频触发优化方式:

  • 防抖:屡次高频操做,只在最后一次执行。策略是当事件被触发时,设定一个周期延迟执行动做,若期间又被触发,则从新设定周期,直到周期结束,执行动做。
function debounce(fn, delay) {
    var timer

    return function () {
        var that = this
        var args = arguments

        clearTimeout(timer)
            timer = setTimeout(function () {
            fn.apply(that, args)
        }, delay)
    }
}
复制代码
  • 节流:每隔一段时间后执行一次。固定周期内,只执行一次动做,如有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。
var throttle = function(func,delay){
    var timer = null;
    var startTime = Date.now();

    return function(){
        var curTime = Date.now();
        var remaining = delay-(curTime-startTime);
        var context = this;
        var args = arguments;

        clearTimeout(timer);
        if(remaining<=0){
            func.apply(context,args);
            startTime = Date.now();
        }else{
            timer = setTimeout(func,remaining);
        }
    }
}

复制代码

SSR服务端渲染

直接在服务端层获取数据,渲染出完成的html文件,直接返回给用户浏览器。

原理:1. Node服务,让先后端运行同一套代码;
      2. Virtual Dom,让前端代码脱离浏览器运行。
条件:Node中间层 / React或vue框架

客户端渲染路线:1. 请求一个html -> 
                2. 服务端返回一个html -> 
                3. 浏览器下载html里面的js/css文件 -> 
                4. 等待js文件下载完成 -> 
                5. 等待js加载并初始化完成 -> 
                6. js代码终于能够运行,由js代码向后端请求数据( ajax/fetch ) -> 
                7. 等待后端数据返回 -> 
                8. 客户端从无到完整地,把数据渲染为响应页面

服务端渲染路线:1. 请求一个html -> 
                2. 服务端请求数据( 内网请求快 ) -> 
                3. 服务器初始渲染(服务端性能好,较快) -> 
                4. 服务端返回已经有正确内容的页面 -> 
                5. 客户端请求js/css文件 -> 
                6. 等待js文件下载完成 -> 
                7. 等待js加载并初始化完成 -> 
                8. 客户端把剩下一部分渲染完成( 内容小,渲染快 )
复制代码

图片懒加载

参考资料:图片懒加载原理及实现

场景:一个页面中不少图片,可是首屏只出现几张,这时若是一次性把图片都加载出来会影响性能。这时能够使用懒加载,页面滚动到可视区在加载。优化首屏加载。
实现:img标签src属性为空或同一空白图片,给一个data-xx属性,里面存放图片真实地址,当页面滚动直至此图片出如今可视区域时,用js取到该图片的data-xx的值赋给src。
优势:页面加载速度快,减轻服务器压力、节约流量,用户体验好。
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/jquery/2.1.0/jquery.min.js"></script>
    <style>
        .container{
            max-width: 800px;
            margin:0 auto;
        }
        .container:after{
            content:"";
            display: block;
            clear:both;
        }
        .container img{
            width:50%;
            height:260px;
            float:left;
        }
    </style>
</head>
<body>
    <div class="container">
        <img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1" data-src="http://img4.imgtn.bdimg.com/it/u=951914923,777131061&fm=26&gp=0.jpg">
        <img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1" data-src="http://img1.imgtn.bdimg.com/it/u=637435809,3242058940&fm=26&gp=0.jpg">
        <img src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690" alt="1" data-src="http://img1.imgtn.bdimg.com/it/u=3990342075,2367006974&fm=200&gp=0.jpg">
    </div>

        <script>

            // 一开始没有滚动的时候,出如今视窗中的图片也会加载
            start();

            // 当页面开始滚动的时候,遍历图片,若是图片出如今视窗中,就加载图片
            var clock; //函数节流
            $(window).on('scroll',function(){
                if(clock){
                    clearTimeout(clock);
                }
                clock = setTimeout(function(){
                    start()
                },200)
            })
            
            function start(){
                 $('.container img').not('[data-isLoading]').each(function () {
                    if (isShow($(this))) {
                        loadImg($(this));
                    }
                })
            }

            // 判断图片是否出如今视窗的函数
            function isShow($node){
                return $node.offset().top <= $(window).height()+$(window).scrollTop();
            }

            // 加载图片的函数,就是把自定义属性data-src 存储的真正的图片地址,赋值给src
            function loadImg($img){
                    $img.attr('src', $img.attr('data-src'));

                    // 已经加载的图片,我给它设置一个属性,值为1,做为标识
                    // 弄这个的初衷是由于,每次滚动的时候,全部的图片都会遍历一遍,这样有点浪费,因此作个标识,滚动的时候只遍历哪些尚未加载的图片
                    $img.attr('data-isLoading',1);
            }
        </script>
</body>
</html>
复制代码

页面渲染步骤

1. 解析HTML,生成DOM树。
    接收HTML文档,遍历文档节点,生成DOM树。
    可能被CSS和JS加载阻塞!
2. 解析CSS,生成CSSOM规则树。
    每一个CSS文件分析成StyleSheet对象,包含CSS规则
3. 将DOM树与CSSOM规则树合并在一块儿,生成渲染树。
    渲染树:用于显示,不可见元素则不在树中。display:none 不在;visibility:hidden 在。
    先从DOM树根节点开始遍历可见节点,找到适配的CSS。
4. 遍历渲染树开始布局。计算每一个节点的位置大小信息。
    从渲染树跟节点开始遍历,肯定节点对象的大小和位置,输出盒子模型。
5. 将渲染树每一个节点绘制到屏幕
    由UI后端组件完成,调用paint()显示内容。
    
渲染阻塞:script标记将使DOM构建暂停。
    若是脚本中操做了CSSOM,则操做顺序 CSSOM => 脚本 => DOM
    CSS引入优先,JS底部置后。
复制代码

js和css阻塞

1. 外部样式会阻塞以后的<script>,但<script>会在<link>以后执行
2. 外部css加载时,外部Js也会加载,只是Js执行必须是css执行以后
3. 使用async属性后,Js异步加载,且没必要等待css以后执行,也不阻塞后面的Js
4. <script>动态建立时,会在css加载以后加载
复制代码

async和defer

参考资料:浅谈script标签中的async和defer

普通script:若是遇到script脚本,就会中止页面的解析进行下载

script
defer:在后台进行下载,可是并不会阻止文档的渲染,当页面解析&渲染完毕后, 会等到全部的defer脚本加载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded事件。
defer
async:async脚本会在加载完毕后执行。async脚本的加载不计入DOMContentLoaded事件统计
async1
async2

其余前端常考知识

路由的Js实现

参考资料:原生 js 实现一个前端路由 router

  1. 实现原理:如今前端的路由实现通常有两种,一种是 Hash 路由,另一种是 History 路由。
  • 2.1. History 路由

    History 接口容许操做浏览器的曾经在标签页或者框架里访问的会话历史记录。

    属性

    History.length 是一个只读属性,返回当前 session 中的 history 个数,包含当前页面在内。举个例子,对于新开一个 tab 加载的页面当前属性返回值 1 。

    History.state 返回一个表示历史堆栈顶部的状态的值。这是一种能够没必要等待 popstate 事件而查看状态而的方式。 方法 History.back()前往上一页, 用户可点击浏览器左上角的返回按钮模拟此方法. 等价于 history.go(-1).

    Note: 当浏览器会话历史记录处于第一页时调用此方法没有效果,并且也不会报错。

    History.forward()在浏览器历史记录里前往下一页,用户可点击浏览器左上角的前进按钮模拟此方法. 等价于 history.go(1).

    Note: 当浏览器历史栈处于最顶端时( 当前页面处于最后一页时 )调用此方法没有效果也不报错。

    History.go(n)经过当前页面的相对位置从浏览器历史记录( 会话记录 )加载页面。好比:参数为 -1的时候为上一页,参数为 1 的时候为下一页. 当整数参数超出界限时 ( 译者注:原文为 When integerDelta is out of bounds ),例如: 若是当前页为第一页,前面已经没有页面了,我传参的值为 -1,那么这个方法没有任何效果也不会报错。调用没有参数的 go() 方法或者不是整数的参数时也没有效果。( 这点与支持字符串做为 url 参数的 IE 有点不一样)。

    history.pushState() 和 history.replaceState()这两个 API 都接收三个参数,分别是

    a. 状态对象(state object) — 一个JavaScript对象,与用 pushState() 方法建立的新历史记录条目关联。不管什么时候用户导航到新建立的状态,popstate 事件都会被触发,而且事件对象的state 属性都包含历史记录条目的状态对象的拷贝。
    
      b. 标题(title) — FireFox 浏览器目前会忽略该参数,虽然之后可能会用上。考虑到将来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也能够传入一个简短的标题,标明将要进入的状态。
    
      c. 地址(URL) — 新的历史记录条目的地址。浏览器不会在调用 pushState() 方法后加载该地址,但以后,可能会试图加载,例如用户重启浏览器。新的 URL 不必定是绝对路径;若是是相对路径,它将以当前 URL 为基准;传入的 URL 与当前 URL 应该是同源的,不然,pushState() 会抛出异常。该参数是可选的;不指定的话则为文档当前 URL。
    
      相同之处: 是两个 API 都会操做浏览器的历史记录,而不会引发页面的刷新。
    
      不一样之处: pushState 会增长一条新的历史记录,而 replaceState 则会替换当前的历史记录。
    复制代码

    例子:

    原本的路由http://biaochenxuying.cn/

    执行:window.history.pushState(null, null, "http://biaochenxuying.cn/home");

    路由变成了:http://biaochenxuying.cn/home

  • 2.2 Hash 路由

    咱们常常在 url 中看到 #,这个 # 有两种状况,一个是咱们所谓的锚点,好比典型的回到顶部按钮原理、Github 上各个标题之间的跳转等,可是路由里的 # 不叫锚点,咱们称之为 hash。

    当 hash 值发生改变的时候,咱们能够经过 hashchange事件监听到,从而在回调函数里面触发某些方法。

<meta>标签:

提供有关页面的源信息,如针对搜索引擎和更新频率的描述和关键词。

必选:content → 名称/值对中的值, 能够是任何有效的字符串。 始终要和 name 属性或 http-equiv 属性一块儿使用。
可选:http-equiv → 没有name时,会采用这个属性的值。经常使用的有content-type、expires、refresh、set-cookie。把content属性关联到http头部。
      name → 名称/值对中的名称。经常使用的有author、description、keywords、generator、revised、others。 把 content 属性关联到一个名称。
      scheme → 用于指定要用来翻译属性值的方案。
<meta http-equiv="charset" content="iso-8859-1">
复制代码

Babel转码器:将ES6转为ES5。

1 将ES6/ES7解析为抽象语法树
2 对抽象语法树进行遍历编译,获得新的抽象语法树
3 将新的抽象语法树转换成ES5

抽象语法树AST:将代码逐字母解析成树状对象。
复制代码

webpack打包过程:

前端资源加载/打包工具。
把项目看成一个总体,经过一个给定的主文件index.js,从这个文件开始找到项目的全部依赖文件,使用Loader处理,最后打包为浏览器可识别的js文件。

1 读取文件,分析模块依赖
2 对模块进行解析执行(深度遍历)
3 针对不一样模块,使用不一样的Loader
4 编译模块,生成抽象语法树AST
5 遍历AST,输出js
复制代码

webpack配置文件

  • Loaders

    • 经过使用不一样的loader,webpack有能力调用外部的脚本或工具,实现对不一样格式的文件的处理

    • 好比说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders能够把React的中用到的JSX文件转换为JS文件。

    • Loaders须要单独安装而且须要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括如下几方面:

      1. test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
      2. loader:loader的名称(必须)
      3. include/exclude: 手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);
      4. query:为loaders提供额外的设置选项(可选)
  • babel

    • babel是一种javascript编译器,它能把最新版的javascript编译成当下能够执行的版本,简言之,利用babel就可让咱们在当前的项目中随意的使用这些新最新的es6,甚至es7的语法。说白了就是把各类javascript千奇百怪的语言通通专为浏览器能够认识的语言。
    • babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中
  • plugins

    • 插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程当中生效,执行相关的任务。
  • Loaders和Plugins经常被弄混,可是他们实际上是彻底不一样的东西,能够这么来讲:

    • loaders是在打包构建过程当中用来处理源文件的(JSX,Scss,Less..),一次处理一个。
    • 插件并不直接操做单个文件,它直接对整个构建过程其做用。

webpack常见的Plugin?他们是解决什么问题的?

(1)uglifyjs-webpack-plugin:经过UglifyJS去压缩js代码;

(2)commons-chunk-plugin:提取公共代码;

(3)define-plugin:定义环境变量。

webpack的热更新是如何作到的?说明其原理?

webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。 这个机制能够作到不用刷新浏览器而将新变动的模块替换掉旧的模块。

原理:

(1)第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块从新编译打包,并将打包后的代码经过简单的 JavaScript 对象保存在内存中。

(2)第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API对代码变化进行监控,而且告诉 webpack,将代码打包到内存中。

(3)第三步是 webpack-dev-server对文件变化的一个监控,这一步不一样于第一步,并非监控代码变化从新打包。当咱们在配置文件中配置了devServer.watchContentBase 为 true 的时候,Server 会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念。

(4)第四步也是 webpack-dev-server 代码的工做,该步骤主要是经过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间创建一个 websocket 长链接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据这些 socket 消息进行不一样的操做。固然服务端传递的最主要信息仍是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。

(5)webpack-dev-server/client 端并不可以请求更新的代码,也不会执行热更模块操做,而把这些工做又交回给了 webpack,webpack/hot/dev-server 的工做就是根据 webpack-dev-server/client 传给它的信息以及 dev-server 的配置决定是刷新浏览器呢仍是进行模块热更新。固然若是仅仅是刷新浏览器,也就没有后面那些步骤了。

(6)HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的 hash 值,它经过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个 json,该 json 包含了全部要更新的模块的 hash 值,获取到更新列表后,该模块再次经过 jsonp 请求,获取到最新的模块代码。这就是上图中 七、八、9 步骤。

(7)而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。

(8)最后一步,当 HMR 失败后,回退到 live reload 操做,也就是进行浏览器刷新来获取最新打包代码。

如何利用webpack来优化前端性能?(提升性能和体验)

用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。

(1)压缩代码。删除多余的代码、注释、简化代码的写法等等方式。能够利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css。使用webpack4,打包项目使用production模式,会自动开启代码压缩。

(2)利用CDN加速。在构建过程当中,将引用的静态资源路径修改成CDN上对应的路径。能够利用webpack对于output参数和各loader的publicPath参数来修改资源路径

(3)删除死代码(Tree Shaking)。将代码中永远不会走到的片断删除掉。能够经过在启动webpack时追加参数--optimize-minimize来实现或者使用es6模块开启删除死代码。

(4)优化图片,对于小图能够使用 base64 的方式写入文件中

(5)按照路由拆分代码,实现按需加载,提取公共代码。

(6)给打包出来的文件名添加哈希,实现浏览器缓存文件

如何提升webpack的构建速度?

(1)多入口的状况下,使用commonsChunkPlugin来提取公共代码;

(2)经过externals配置来提取经常使用库;

(3)使用happypack实现多线程加速编译;

(4)使用webpack-uglify-parallel来提高uglifyPlugin的压缩速度。原理上webpack-uglify-parallel采用多核并行压缩来提高压缩速度;

(5)使用tree-shaking和scope hoisting来剔除多余代码。

十一、怎么配置单页应用?怎么配置多页应用?

单页应用能够理解为webpack的标准模式,直接在entry中指定单页应用的入口便可。

多页应用的话,能够使用webpack的 AutoWebPlugin来完成简单自动化的构建,可是前提是项目的目录结构必须遵照他预设的规范。

npm打包时须要注意哪些?如何利用webpack来更好的构建?

NPM模块须要注意如下问题:

(1)要支持CommonJS模块化规范,因此要求打包后的最后结果也遵照该规则

(2)Npm模块使用者的环境是不肯定的,颇有可能并不支持ES6,因此打包的最后结果应该是采用ES5编写的。而且若是ES5是通过转换的,请最好连同SourceMap一同上传。

(3)Npm包大小应该是尽可能小(有些仓库会限制包大小)

(4)发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样能够避免模块应用者再次打包时出现底层模块被重复打包的状况。

(5)UI组件类的模块应该将依赖的其它资源文件,例如.css文件也须要包含在发布的模块里。

基于以上须要注意的问题,咱们能够对于webpack配置作如下扩展和优化:

(1)CommonJS模块化规范的解决方案: 设置output.libraryTarget='commonjs2'使输出的代码符合CommonJS2 模块化规范,以供给其它模块导入使用;

(2)输出ES5代码的解决方案:使用babel-loader把 ES6 代码转换成 ES5 的代码。再经过开启devtool: 'source-map'输出SourceMap以发布调试。

(3)Npm包大小尽可能小的解决方案:Babel 在把 ES6 代码转换成 ES5 代码时会注入一些辅助函数,最终致使每一个输出的文件中都包含这段辅助函数的代码,形成了代码的冗余。解决方法是修改.babelrc文件,为其加入transform-runtime插件

(4)不能将依赖模块打包到NPM模块中的解决方案:使用externals配置项来告诉webpack哪些模块不须要打包。

(5)对于依赖的资源文件打包的解决方案:经过css-loader和extract-text-webpack-plugin来实现,配置以下:

如何在vue项目中实现按需加载?

常常会引入现成的UI组件库如ElementUI、iView等,可是他们的体积和他们所提供的功能同样,是很庞大的。 不过不少组件库已经提供了现成的解决方案,如Element出品的babel-plugin-component和AntDesign出品的babel-plugin-import安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,便可实现组件按需加载了。

webpack开发配置API代理解决跨域问题

使用的是http-proxy-middleware来实现跨域代理

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {  → 捕获API的标志,开始匹配代理,好比API请求/api/users, 会被代理到请求 http://www.baidu.com/api/users 。
        target: 'http://www.baidu.com/', → 代理的API地址,就是须要跨域的API地址。地址能够是域名,也能够是IP地址,若是是域名须要额外添加一个参数changeOrigin: true
        pathRewrite: {'^/api' : ''}, → 路径重写,也就是说会修改最终请求的API路径。目的是给代理命名后,在访问时把命名删除掉。
        changeOrigin: true,     // 让target参数是域名
        secure: false,          // 不检查安全问题。设置后,能够接受运行在 HTTPS 上,能够使用无效证书的后端服务器
      },
      '/api2': {
          .....
      }
    }
  }
};
复制代码

package.json 常见字段

{
  // 名称
  "name": "vue",
  // 版本
  "version": "2.6.10",
  // 描述
  "description": "Reactive, component-oriented view layer for modern web interfaces.",
  // npm包项目的主要入口文件,必须的
  "main": "dist/vue.runtime.common.js",
  // rollup 打包须要的入口文件
  "module": "dist/vue.runtime.esm.js",
  // npm 上全部的文件都开启 cdn 服务地址
  "unpkg": "dist/vue.js",
  // jsdelivr cdn公共库
  "jsdelivr": "dist/vue.js",
  // TypeScript 的入口文件
  "typings": "types/index.d.ts",
  // 当你发布package时,具体那些文件会发布上去
  "files": [
    "src",
    "dist/*.js",
    "types/*.d.ts"
  ],
  // 声明该模块是否包含 sideEffects(反作用),从而能够为 tree-shaking 提供更大的优化空间。
  "sideEffects": false,
  "scripts": {
    "dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
    "build": "node scripts/build.js",
    "test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
    "commit": "git-cz"
    ......
  },
  // 代码质量检查
  "gitHooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "node scripts/verify-commit-msg.js"
  },
  // 代码检查
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ]
  },
  // git仓库所在位置
  "repository": {
    "type": "git",
    "url": "git+https://github.com/vuejs/vue.git"
  },
  // 关键词
  "keywords": [
    "vue"
  ],
  // 做者
  "author": "Evan You",
  // 开源协议
  "license": "MIT",
  // bug地址
  "bugs": {
    "url": "https://github.com/vuejs/vue/issues"
  },
  // 主页
  "homepage": "https://github.com/vuejs/vue#readme",
  // 依赖
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.1.0",
    "acorn": "^5.2.1",
    "babel-eslint": "^10.0.1",
    "eslint": "^5.7.0",
    ......
  },
  // 设置一些用于npm包的脚本命令会用到的配置参数
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  }
  // 本node包依赖的其余依赖包
    "peerDependencies": {
        "vue": "^2.5.2"
    },
    // 指明了该项目所须要的node.js版本
    "engines": {
        "node": ">=8.9.1",
        "npm": ">=5.5.1",
        "yarn": ">=1.3.2"
    },
    // 支持的浏览器
    "browserslist": [
        "last 3 Chrome versions",
        "last 3 Firefox versions",
        "Safari >= 10",
        "Explorer >= 11",
        "Edge >= 12",
        "iOS >= 10",
        "Android >= 6"
    ]
}
复制代码

web兼容性问题

参考资料:web前端兼容性问题总结

MVC和MVVM

参考资料:浅析前端开发中的 MVC/MVP/MVVM 模式

  • Model层:用于封装和应用程序的业务逻辑相关的数据 [和对应处理数据的方法]。
  • View层:做为视图层,主要负责数据的展现。
  • controller层:定义用户界面对用户输入的响应方式,链接模型和视图,用于控制应用程序的流程,处理用户的行为和数据上的改变。

MVC:容许在不改变视图的状况下改变视图对用户输入的响应方式,用户对View的操做交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操做,一旦Model发生变化便通知相关视图进行更新。

MVP:是MVC模式的改良。Controller/Presenter负责业务逻辑,Model管理数据,View负责显示。 MVP中的View并不能直接使用Model,而是经过为Presenter提供接口,让Presenter去更新Model,再经过观察者模式更新View。 解耦View和Model,彻底分离视图和模型使职责划分更加清晰;因为View不依赖Model,能够将View抽离出来作成组件,它只须要提供一系列接口提供给上层操做。

MVVM:把View和Model的同步逻辑自动化了。View和Model同步再也不手动地进行操做,而是交给框架所提供的数据绑定功能进行负责,只须要告诉它View显示的数据对应的是Model哪一部分便可。View经过使用模板语法来声明式的将数据渲染进DOM,当ViewModel对Model进行更新的时候,会经过数据绑定更新到View。

设计模式

参考资料:JavaScript设计模式 单例模式

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
实现方法:先判断实例存在与否,若是存在则直接返回,若是不存在就建立了再返回,这就确保了一个类只有一个实例对象。
适用场景:一个单一对象。好比:弹窗,不管点击多少次,弹窗只应该被建立一次。
复制代码

发布/订阅模式

定义:又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都将获得通知。
场景:订阅感兴趣的专栏和公众号。
复制代码

策略模式

定义:将一个个算法(解决方案)封装在一个个策略类中。
优势:策略模式能够避免代码中的多重判断条件。
      策略模式很好的体现了开放-封闭原则,将一个个算法(解决方案)封装在一个个策略类中。便于切换,理解,扩展。
      策略中的各类算法能够重复利用在系统的各个地方,避免复制粘贴。
      策略模式在程序中或多或少的增长了策略类。但比堆砌在业务逻辑中要清晰明了。
      违反最少知识原则,必需要了解各类策略类,才能更好的在业务中应用。
应用场景:根据不一样的员工绩效计算不一样的奖金;表单验证中的多种校验规则。
复制代码

单页面应用

在一个页面上集成多种功能,全部业务功能都是子版块,经过特定的方式挂接到主界面上。
采用MV*框架,在JS层建立模块分层和通讯机制。
代码隔离:
    子功能代码隔离
    页面模板隔离
样式规划:
    基准样式分离(浏览器样式、全局样式、布局、响应支持
    组件样式划分(界面组件及子元素样式、修饰样式)
    堆叠次序管理(提早为UI组件规划次序)
先后端自然分离,以API为分界
缺陷:不利于搜索引擎优化
把产品功能划分为若干状态,每一个状态映射到相应的路由
在非首次请求中,使用缓存或本地存储
采用websocket实时通信。前端只响应确实产生业务数据的事件。
复制代码

单页面应用的优劣

  • 优势:

    • 分离先后端关注点,前端负责界面显示,后端负责数据存储和计算,各司其职,不会把先后端的逻辑混杂在一块儿;
    • 易于代码复用,同一套后端程序代码,不用修改就能够用于Web界面、手机、平板等多种客户端;
    • 页面切换速度快。视觉上页面的切换,只是技术上同一页面两个区块之间的切换
  • 缺点:

    • SEO问题,如今能够经过Prerender等技术解决一部分;
    • 前进、后退、地址栏等,须要程序进行管理;
    • 书签,须要程序来提供支持;
    • 请求资源大小增长,打开页面速度变慢,能够经过拆分加载解决

web性能优化

资料参考:嗨,送你一张Web性能优化地图

性能优化

  • 度量标准

    1. 首次有效绘制(First Meaningful Paint,简称FMP,当主要内容呈如今页面上)
    2. 英雄渲染时间(Hero Rendering Times,度量用户体验的新指标,当用户最关心的内容渲染完成)
    3. 可交互时间(Time to Interactive,简称TTI,指页面布局已经稳定,关键的页面字体是可见的,而且主进程可用于处理用户输入,基本上用户能够点击UI并与其交互)
    4. 输入响应(Input responsiveness,界面响应用户输入所需的时间)
    5. 感知速度指数(Perceptual Speed Index,简称PSI,测量页面在加载过程当中视觉上的变化速度,分数越低越好)
    6. 自定义指标,由业务需求和用户体验来决定。
  • 编码优化

    1. 数据读取速度:对象嵌套的越深,读取速度就越慢;对象在原型链中存在的位置越深,找到它的速度就越慢
    2. DOM:尽量减小访问DOM的次数;减小重排与重绘的次数;善于使用事件委托
    3. 流程控制:减小迭代的次数;基于循环的迭代比基于函数的迭代快8倍;在JS中倒序循环会略微提高性能
  • 静态资源优化

    1. 使用Brotli或Zopfli进行纯文本压缩
    2. 图片优化:尽量经过srcset,sizes和元素使用响应式图片。
  • 交付优化:对页面加载资源以及用户与网页之间的交付过程进行优化

    1. 异步无阻塞加载JS:将Script标签放到页面的最底部;使用defer或async
    2. 使用Intersection Observer实现懒加载:延迟加载图片、视频、广告脚本、或任何其余资源
    3. 优先加载关键的CSS:将首屏渲染必须用到的CSS提取出来内嵌到中,而后再将剩余部分的CSS用异步的方式加载
    4. 资源提示:Resource Hints
    5. Preload:经过一个现有元素(例如:img,script,link)声明资源会将获取与执行耦合在一块儿
    6. 快速响应的用户界面:使用骨架屏或添加一些Loading过渡动画提示用户体验
  • 构建优化:影响构建后文件的体积、代码执行效率、文件加载时间、首次有效绘制指标

    1. 使用预编译
    2. 使用 Tree-shaking、Scope hoisting、Code-splitting
    3. 服务端渲染(SSR):使用服务端渲染静态HTML来得到更快的首次有效绘制,一旦JavaScript加载完毕再将页面接管下来
    4. 使用import函数动态导入模块,按需加载
    5. 使用HTTP缓存头:推荐使用Cache-control: immutable避免从新验证

静态资源优化

资料参考:Web前端性能优化——如何有效提高静态文件的加载速度

  1. 代码压缩 使用webpack
  2. 文件合并 合并js脚本文件 合并css样式文件
  3. 在webpack的配置中增长gzip压缩配置
  4. CDN和缓存

App端网页和PC端网页设计起来有什么区别?

1. 手机网页主要webkit,PC网页主要ie。且手机端须要跨系统平台
2. app端,须要基于phoneGap调用手机核心功能接口(地理定位、联系人、加速器、声音、振动)。模拟tive app,编译成各系统平台的app
3. 设置高度、宽度是否能缩放。
    <meta name="viewPort" content="width=device-width,inital-scale=1.0, minimun-scale=0.5,maximum=scale=1.0,user-scalable=no"
4. 自适应,对不一样像素的屏幕写不一样的样式
    @media only screen and (min-device-width:320px) and (max-device-width:480){...}
5. 用户体验不一样(鼠标与触屏)
复制代码

计算在一个页面上的停留时间

方案1:websocket,前端开个长链接,后台统计长链接时间。
方案2:ajax轮询,隔几秒发一个查询,后台记录第一与最后一个查询间隔时间。
方案3:关闭窗口或者跳转的时候会触发window.onbeforeunload函数,能够在该函数中作处理(有兼容性问题);统计完数据记录到本地cookies中,一段时间后统一发送。
复制代码

浏览器内核有哪些,移动端用的是哪一个

Trident内核:IE,MaxThon,TT,The Word,360,搜狗浏览器等。[又称为MSHTML]
Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等;
Presto内核:Opera7及以上。[Opera内核原为:Presto,现为:Blink]
Webkit内核:Safari,Chrome等。[Chrome的:Blink(Webkit的分支)]

对于Android手机而言,使用率最高的就是Webkit内核。
复制代码

其余

至今遇到印象最深的bug(最好是搜索不到的)

印象最深的项目

是否了解最新技术,前端技术更新的见解

为何要作前端

将来的职业规划

平时是怎么学习的

为何选择x公司

相关文章
相关标签/搜索