-
常见的浏览器内核,参见下表:
浏览器/RunTime | 内核(渲染引擎) | JavaScript 引擎 |
---|
Chrome | Blink(28~) Webkit(Chrome 27) | V8 |
FireFox | Gecko | SpiderMonkey |
Safari | Webkit | JavaScriptCore |
Edge | EdgeHTML | Chakra(for JavaScript) |
IE | Trident | Chakra(for JScript) |
PhantomJS | Webkit | JavaScriptCore |
Node.js | - | V8 |
-
判断浏览器内核
判断是否原生Chrome:只有原生Chrome中存在一种MimeType“application/vnd.chromium.remoting-viewer”,由此可以判断浏览器是加壳Chrome或是原生Chrome。
判断是否为IE浏览器:只有IE内核的浏览器存在ActiveXObject对象。由此可以判断是否为IE浏览
-
从输入 URL 到页面加载完成,发生了什么?
首先我们需要通过 DNS(域名解析系统)将 URL 解析为对应的 IP 地址,然后与这个 IP 地址确定的那台服务器建立起 TCP 网络连接,随后我们向服务端抛出我们的 HTTP 请求,服务端处理完我们的请求之后,把目标数据放在 HTTP 响应里返回给客户端,拿到响应数据的浏览器就可以开始走一个渲染的流程。渲染完毕,页面便呈现给了用户。
0)输入url 读取浏览器缓存 系统缓存 路由缓存,若匹配到则直接展示
1)DNS 解析:
2) TCP 连接:
3) HTTP 请求抛出
4) 服务端处理请求,HTTP 响应返回
5) 浏览器拿到响应数据,解析响应内容,把解析的结果展示给用户
-
浏览器重绘与重排的区别?
重排: 部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算,表现为重新生成布局,重新排列元素
重绘: 由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新,表现为某些元素的外观被改变
单单改变元素的外观,肯定不会引起网页重新生成布局,但当浏览器完成重排之后,将会重新绘制受到此次重排影响的部分
重排和重绘代价是高昂的,它们会破坏用户体验,并且让UI展示非常迟缓,而相比之下重排的性能影响更大,在两者无法避免的情况下,一般我们宁可选择代价更小的重绘。
『重绘』不一定会出现『重排』,『重排』必然会出现『重绘』。
-
如何触发重排和重绘?
任何改变用来构建渲染树的信息都会导致一次重排或重绘:
添加、删除、更新DOM节点
通过display: none隐藏一个DOM节点-触发重排和重绘
通过visibility: hidden隐藏一个DOM节点-只触发重绘,因为没有几何变化
移动或者给页面中的DOM节点添加动画
添加一个样式表,调整样式属性
用户行为,例如调整窗口大小,改变字号,或者滚动
-
如何避免重绘或者重排?
集中改变样式:通过改变class的方式来集中改变样式
// 判断是否是黑色系样式
const theme = isDark ? 'dark' : 'light'
// 根据判断来设置不同的class
ele.setAttribute('className', theme)
使用DocumentFragment:通过createDocumentFragment创建一个游离于DOM树之外的节点,然后在此节点上批量操作,最后插入DOM树中,因此只触发一次重排
var fragment = document.createDocumentFragment();
for (let i = 0;i<10;i++){
let node = document.createElement("p");
node.innerHTML = i;
fragment.appendChild(node);
}
document.body.appendChild(fragment);
提升为合成层:提升合成层的最好方式是使用 CSS 的 will-change 属性
#target {
will-change: transform;
}
-
前端如何实现即时通讯?
1)短轮询
2)comet
3)SSE
4)Websocket
5)Web Worker
6)Service workers
HTTP 协议有一个缺陷:通信只能由客户端发起。举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,可以用另一种方法 WebSocket 。
- Websocket
WebSocket 协议最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。 特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
WebSocket 的用法
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
客户端的 API
1)WebSocket() 构造函数,用于新建 WebSocket 实例。执行下面语句之后,客户端就会与服务器进行连接。 var ws = new WebSocket('ws://localhost:8080');
2)webSocket.readyState
3)webSocket.onopen
4)webSocket.onclose
5)webSocket.onmessage
6)webSocket.send()
7)webSocket.bufferedAmount
8)webSocket.onerror
服务端的实现 常用的 Node 实现有以下三种
µWebSockets
Socket.IO
WebSocket-Node
推荐一款非常特别的 WebSocket 服务器:Websocketd。
- 浏览器跨域问题解决(九种跨域方式)
最经典的跨域方案jsonp
最流行的跨域方案cors
最方便的跨域方案nginx反向代理
postMessage()
websocket
window.name + iframe
location.hash + iframe
二级域名相同 document.domain + iframe
其它跨域方案: node中间件代理 -
常见web安全及防护
web安全受到的威胁来自于以下几种攻击方式:
sql注入,
xss(恶意注入js和网页元素),
csrf(代替用户完成交互并访问危险网站)
我们的防护:
1)对用户输入内容进行限制和校验
2)对所有关键数据进行加密
3)接口提交方式严格规范,数据提交不使用get
-
浏览器存储和服务端存储
cookie和session的区别
1)存储位置有区分,cookie存在浏览器缓存中,session存储在服务器上
2)存储大小和数量 cookie小于session
3)保密性 cookie对游览器和用户可见 session存在服务器上,保密性更佳
4)服务器压力 session对服务器压力更大
在实际开发过程中,cookie和session都很少使用,更为常用的是token,它比上两个优势更大,更好用,安全性高,可扩展性强,多平台跨域,无状态。可实现,单点登录和多点登录等功能。
不要混淆session和session Storage
session是身份验证(类似于令牌),session是一次浏览器和服务器的交互的会话,当访问服务器这个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做session,而这个内存是跟浏览器关联在一起的。这个浏览器指的是浏览器窗口或浏览器的子窗口,意思就是,只允许当前这个session对应的浏览器访问,就算是在同一个机器上新启的浏览器也是无法访问的。而另外一个浏览器也需要记录session的话,就会再启一个属于自己的session
session Storage是一种存储方式,数据保存在浏览器缓存中,关闭浏览器和标签页就会消失。特别的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 Session Storage 内容便无法共享。
local Storage存储在本地需要手动删除才会消失,理论上 Cookie 无法胜任的、可以用简单的键值对来存取的数据存储任务,都可以交给 Local Storage 来做。存储一些内容稳定的资源。比如图片内容丰富的电商网站会用它来存储 Base64 格式的图片字符串,存储一些不经常更新的 CSS、JS 等静态资源。
cookie是把少量的信息存储在用户端浏览器缓存中,它是全局的,在同一个域名下的所有请求,都会携带 Cookie。很快速方便。而且它本身存储的尺寸大小也有限 4k左右,最关键是用户是可见的,并可以随意的修改,很不安全。Cookie 虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie 带来的开销将是无法想象的。静态资源往往并不需要 Cookie 携带什么认证信息。把静态资源和主页面置于不同的域名下,完美地避免了不必要的 Cookie 的出现!
cookies和localStorage和sessionStorage是同一类,都是储存方式,都遵循同源策略。只是大小,保存位置,保存时间不一样 大小 cookies<sessionStorage=localStorage 5-10M 之间
保存位置 本地
IndexedDB
IndexedDB 是没有存储上限的(一般来说不会小于 250M)
IndexedDB 可以看做是 LocalStorage 的一个升级,当数据的复杂度和规模上升到了 LocalStorage 无法解决的程度,我们毫无疑问可以请出 IndexedDB 来帮忙。
- 前端造成内存泄漏的操作
1)闭包由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,过多的使用闭包,不及时释放,会导致内存泄漏。
2)意外全局函数中定义参数,var 定义,会成为全局变量,使用es6的let可以避免这种情况。
3)定时器
4)生命周期中使用全局函数,未释放
5)echarts
6)keep-alive组件
什么是内存泄漏?
基于垃圾回收机制,当有变量和对象应该被回收而没有被回收时,一直占用和停留在堆内存中,这就产生内存泄漏。
内存泄漏会导致内存被占用过多无法释放,从而导致系统内存分配不足,造成了内存溢出从而导致应用Crash(浏览器崩溃)。
还有对于现在电脑来说,一些内存泄漏并不影响。
-
性能监控
performance
function getsec(time) {
return time / 1000 + 's'
}
window.onload = function () {
var per = window.performance.timing;
console.log('DNS查询耗时' + getsec(per.domainLookupEnd - per.domainLookupStart))
console.log('TCP链接耗时' + getsec(per.connectEnd - per.connectStart))
console.log('request请求响应耗时' + getsec(per.responseEnd - per.responseStart))
console.log('dom渲染耗时' + getsec(per.domComplete - per.domInteractive))
console.log('白屏时间' + getsec(firstPaint - pageStartTime))
console.log('domready可操作时间' + getsec(per.domContentLoadedEventEnd - per.fetchStart))
}