面试题来源于个人项目「前端面试与进阶指南」css
本章关于浏览器原理部分的内容主要来源于浏览器工做原理,这是一篇很长的文章,能够算上一本小书了,有精力的很是建议阅读。html
浏览器/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 浏览器的每一个标签页都分别对应一个呈现引擎实例。每一个标签页都是一个独立的进程。html5
浏览器会『从右往左』解析CSS选择器。java
咱们知道DOM Tree与Style Rules合成为 Render Tree,其实是须要将Style Rules附着到DOM Tree上,所以须要根据选择器提供的信息对DOM Tree进行遍历,才能将样式附着到对应的DOM元素上。node
如下这段css为例nginx
.mod-nav h3 span {font-size: 16px;}
复制代码
咱们对应的DOM Tree 以下git
若从左向右的匹配,过程是:程序员
若是从右至左的匹配:github
后者匹配性能更好,是由于从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);而从左向右的匹配规则的性能都浪费在了失败的查找上面。
单单改变元素的外观,确定不会引发网页从新生成布局,但当浏览器完成重排以后,将会从新绘制受到这次重排影响的部分
重排和重绘代价是高昂的,它们会破坏用户体验,而且让UI展现很是迟缓,而相比之下重排的性能影响更大,在二者没法避免的状况下,通常咱们宁肯选择代价更小的重绘。
『重绘』不必定会出现『重排』,『重排』必然会出现『重绘』。
任何改变用来构建渲染树的信息都会致使一次重排或重绘:
咱们每每经过改变class的方式来集中改变样式
// 判断是不是黑色系样式
const theme = isDark ? 'dark' : 'light'
// 根据判断来设置不一样的class
ele.setAttribute('className', theme)
复制代码
咱们能够经过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;
}
复制代码
关于合成层的详解请移步无线性能优化:Composite
短轮询的原理很简单,每隔一段时间客户端就发出一个请求,去获取服务器最新的数据,必定程度上模拟实现了即时通信。
comet有两种主要实现手段,一种是基于 AJAX 的长轮询(long-polling)方式,另外一种是基于 Iframe 及 htmlfile 的流(streaming)方式,一般被叫作长链接。
具体两种手段的操做方法请移步Comet技术详解:基于HTTP长链接的Web端实时通讯技术
长轮询优缺点:
长链接优缺点:
使用指南请看Server-Sent Events 教程
SSE(Server-Sent Event,服务端推送事件)是一种容许服务端向客户端推送新数据的HTML5技术。
使用指南请看WebSocket 教程
Websocket是一个全新的、独立的协议,基于TCP协议,与http协议兼容、却不会融入http协议,仅仅做为html5的一部分,其做用就是在服务器和客户端之间创建实时的双向通讯。
后面性能优化部分会用到,先作了解
Web Worker 的做用,就是为 JavaScript 创造多线程环境,容许主线程建立 Worker 线程,将一些任务分配给后者运行
后面性能优化部分会用到,先作了解
Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也能够在网络可用时做为浏览器和网络间的代理,建立有效的离线体验。
同源策略限制了从同一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
同源是指"协议+域名+端口"三者相同,即使两个不一样的域名指向同一个ip地址,也非同源。
下表给出了相对http://store.company.com/dir/page.html同源检测的示例:
浏览器中的大部份内容都是受同源策略限制的,可是如下三个标签能够不受限制:
<img src=XXX>
<link href=XXX>
<script src=XXX>
跨域是个比较古老的命题了,历史上跨域的实现手段有不少,咱们如今主要介绍三种比较主流的跨域方案,其他的方案咱们就不深刻讨论了,由于使用场景不多,也不必记这么多奇技淫巧。
jsonp本质上是一个Hack,它利用<script>
标签不受同源策略限制的特性进行跨域操做。
jsonp优势:
jsonp的缺点:
<script>
标签只能get)jsonp的实现:
function JSONP({ url, params, callbackKey, callback }) {
// 在参数里制定 callback 的名字
params = params || {}
params[callbackKey] = 'jsonpCallback'
// 预留 callback
window.jsonpCallback = callback
// 拼接参数字符串
const paramKeys = Object.keys(params)
const paramString = paramKeys
.map(key => `${key}=${params[key]}`)
.join('&')
// 插入 DOM 元素
const script = document.createElement('script')
script.setAttribute('src', `${url}?${paramString}`)
document.body.appendChild(script)
}
JSONP({
url: 'http://s.weibo.com/ajax/jsonp/suggestion',
params: {
key: 'test',
},
callbackKey: '_cb',
callback(result) {
console.log(result.data)
}
})
复制代码
cors是目前主流的跨域解决方案,跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不一样源服务器上的指定的资源。当一个资源从与该资源自己所在的服务器不一样的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
若是你用express,能够这样在后端设置
//CORS middleware
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://example.com');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
//...
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'cool beans' }));
app.use(express.methodOverride());
app.use(allowCrossDomain);
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
复制代码
在生产环境中建议用成熟的开源中间件解决问题。
nginx是一款极其强大的web服务器,其优势就是轻量级、启动快、高并发。
如今的新项目中nginx几乎是首选,咱们用node或者java开发的服务一般都须要通过nginx的反向代理。
反向代理的原理很简单,即全部客户端的请求都必须先通过nginx的处理,nginx做为代理服务器再讲请求转发给node或者java服务,这样就规避了同源策略。
#进程, 可更具cpu数量调整
worker_processes 1;
events {
#链接数
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#链接超时时间,服务器会在这个时间事后关闭链接。
keepalive_timeout 10;
# gizp压缩
gzip on;
# 直接请求nginx也是会报跨域错误的这里设置容许跨域
# 若是代理地址已经容许跨域则不须要这些, 不然报错(虽然这样nginx跨域就没意义了)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
# srever模块配置是http模块中的一个子模块,用来定义一个虚拟访问主机
server {
listen 80;
server_name localhost;
# 根路径指到index.html
location / {
root html;
index index.html index.htm;
}
# localhost/api 的请求会被转发到192.168.0.103:8080
location /api {
rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前缀, 不然会出现404
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.0.103:8080; # 转发地址
}
# 重定向错误页面到/50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
复制代码
其他方案来源于九种跨域方式
参考文章:
想要实时关注笔者最新的文章和最新的文档更新请关注公众号程序员面试官,后续的文章会优先在公众号更新.
简历模板: 关注公众号回复「模板」获取
《前端面试手册》: 配套于本指南的突击手册,关注公众号回复「fed」获取