1.前端基础
1.1 prototype和 proto 的关系是什么
-
.__proto__ ===.contructor.prototype
-
//如果一个对象是通过Object.create函数构造出来的,那其__proto__就不一定是.constructor.prototype了
-
//属性返回对创建此对象的数组函数的引用。
1.2 meta viewport原理
-
layout viewport //某些网站会因为viewport太窄而显示错乱,浏览器就默认会把viewport设为一个较宽的值,比如980px。宽度可以通过 document.documentElement.clientWidth来获取
-
visual viewport //代表浏览器可视区域的大小,宽度可以通过 document.documentElement.innerWidth来获取。
-
ideal viewport //是一个能完美适配移动设备的viewport,不同的设备有不同的ideal viewport。
1.3 域名收敛是什么
-
# 浏览器的并发限制:
-
浏览器对于同一域名下允许的并发请求数作了限制,通常同一域名下最大并发请求数为6个;
-
# 域名发散:
-
域名发散就是为了突破浏览器对于同一域名并发请求数的限制,使用域名发散为同一个服务申请多个域名,从而可以一定程度上提高并发量;当然,由于建立新的请求需要一定的代价,因此需要在域名发散与域名收敛间进行trade off,通常发散的域名个数为2-4个;
-
# 域名收敛:
-
域名收敛就是将静态资源放在一个域名下不进行发散,这主要是为了适应移动端的发展需求;通常DNS是一个开销较大的操作,而移动端由于网络带宽和实时性、资源等的限制,这些开销对移动端的用户体验是致命的,因此需要进行域名收敛;
1.4 float和display:inline-block;的区别
-
共性:
-
①inline-block: 是把一个元素的display设置为块状内联元素,意思就是说,让一个元素的容器inline展示,并且里面的内容block展示;inline属性使元素内联展示,内联元素设置宽度无效,相邻的inline元素会在一行显示不换行,直到本行排满为止。block的元素始终会独占一行,呈块状显示,可设置宽高。所以inline-block的元素就是宽高可设置,相邻的元素会在一行显示,直到本行排满,也就是让元素的容器属性为block,内容为inline。
-
②float: 设置元素的浮动为左或者右浮动,当设置元素浮动时,相邻元素会根据自身大小,排满一行,如果父容器宽度不够则会换行。当我们设置了元素的浮动时,这个元素就脱离了文档流,相邻元素会呈环绕装排列。
-
两者共同点是都可以实现元素在一行显示,并且可以自由设置元素大小。
-
区别:
-
①inline-block: 水平排列一行,即使元素高度不一,也会以高度最大的元素高度为行高,即使高度小的元素周围留空,也不回有第二行元素上浮补位。可以设置默认的垂直对齐基线。
-
②float: 让元素脱离当前文档流,呈环绕装排列,如遇上行有空白,而当前元素大小可以挤进去,这个元素会在上行补位排列。默认是顶部对齐。
1.5 前端优化策略列举
-
一、页面级优化
-
1. 减少 HTTP请求数
-
减少 HTTP请求数的主要途径包括:
-
(1). 从设计实现层面简化页面
-
(2). 合理设置 HTTP缓存
-
(3). 资源合并与压缩
-
(4). CSS Sprites
-
(5). Inline Images
-
(6). Lazy Load Images
-
2. 将外部脚本置底(将脚本内容在页面信息内容加载后再加载)
-
3. 异步执行 inline脚本(其实原理和上面是一样,保证脚本在页面内容后面加载。)
-
4. Lazy Load Javascript(只有在需要加载的时候加载,在一般情况下并不加载信息内容。),可以通过构建工具实现,比如配合路由加载
-
5. 将 CSS放在 HEAD中
-
6. 减少不必要的 HTTP跳转
-
7. 避免重复的资源请求
-
二、代码级优化
-
1.Reflow & Repaint
-
reflow:几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
-
repaint:如果只是改变某个元素的背景色、文 字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器 repaint(重绘)。repaint 的速度明显快于 reflow
-
(1):不要通过父级来改变子元素样式,最好直接改变子元素样式,改变子元素样式尽可能不要影响父元素和兄弟元素的大小和尺寸
-
(2):尽量通过class来设计元素样式,切忌用style
-
2.慎用 with
-
with(obj){ p = 1}; 代码块的行为实际上是修改了代码块中的 执行环境 ,将obj放在了其作用域链的最前端,在 with代码块中访问非局部变量是都是先从 obj上开始查找,如果没有再依次按作用域链向上查找,因此使用 with相当于增加了作用域链长度。而每次查找作用域链都是要消耗时间的,过长的作用域链会导致查找性能下降。
-
3.避免使用 eval和 Function
-
4.减少作用域链查找(这方面设计到一些内容的相关问题)
-
作用域链查找问题,这一点在循环中是尤其需要注意的问题。如果在循环中需要访问非本作用域下的变量时请在遍历之前用局部变量缓存该变量,并在遍历结束后再重写那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问时的查找次数是最多的。
-
5.数据访问
-
Javascript中的数据访问包括直接量 (字符串、正则表达式 )、变量、对象属性以及数组,其中对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。
-
6.字符串拼接
-
在 Javascript中使用"+" 号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生成新的字符串变量,然后将拼接结果赋值给新变量。与之相比更为高效的做法是使用数组的 join方法,即将需要拼接的字符串放在数组中最后调用其 join方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑用此方法。
-
7.CSS选择符
-
8.Image压缩
-
9.完整的前端优化还应该包括很多其他的途径,例如 CDN、 Gzip、多域名、无 Cookie服务器
1.6 首屏、白屏时间如何计算
-
//load: 页面上所有的资源(图片,音频,视频等)被加载以后才会触发load事件
-
//DOMContentLoaded: 当文档中没有脚本时,浏览器解析完文档便能触发(ie6/7 onreadystatechange;ie<5 document.documentElement.doScroll("left"))
-
通常认为浏览器开始渲染 <body> 标签或者解析完 <head> 标签的时刻就是页面白屏结束的时间点。但是得考虑到css和js的阻塞。”加载是并行的,执行是串行的“的结果。html开始加载的时候,浏览器会将页面外联的css文件和js文件并行加载,如果一个文件还没回来,它后面的代码是不会执行的。刚刚我们的demo,我们阻塞了css文件几秒,此时js文件因为并行已经加载回来,但由于css文件阻塞住,所以后面 JsStartTime 的赋值语句是不执行的!当我们放开阻塞,此时才会运行到 JsStartTime 的赋值、js文件的解析、JsEndTime的赋值,由于大头时间加载早已完成,所以 JsEndTime 和 JsStartTime 的差值非常小。
1.7 闭包
-
//闭包是函数和声明该函数的词法环境的组合,简单的说就是通过函数保留词法环境
-
function makeAdder(x) {
-
return function(y) {
-
return x + y;
-
};
-
}
-
var add5 = makeAdder(5);
-
var add10 = makeAdder(10);
-
console.log(add5(2)); // 7
-
console.log(add10(2)); // 12
-
//应用
-
for(var i=0;i<severalObj.length;i++){
-
(function(i){
-
severalObj[i].οnclick=function(){......}
-
})(i);
-
}
1.8 作用域链
-
作用域链: 当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端始终是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量,即arguments对象。作用域链的下一个变量对象来自包含环境,而在下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。
-
执行环境(Execution Context): 每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行后,栈将其环境弹出,把控制权返回给之前的执行环境。
-
执行环境的建立分为两个阶段:进入执行上下文(创建阶段)和执行阶段(激活/执行阶段)
-
(1)进入上下文阶段:发生在函数调用时,但在执行具体代码之前。具体完成创建作用域链;创建变量、函数和参数以及求this的值
-
(2)执行代码阶段:主要完成变量赋值、函数引用和解释/执行其他代码
-
总的来说可以将执行上下文看作是一个对象
-
变量对象(Variable Object):每一个执行环境都对应一个变量对象,在该执行环境中定义的所有变量和函数都存放在其对应的变量对象中。
-
(1)进入执行上下文时,VO的初始化过程如下:
-
函数的形参:变量对象的一个属性,其属性名就是形参的名字,其值就是实参的值;对于没有传递的参数,其值为undefined;
-
函数声明:变量对象的一个属性,其属性名和属性值都是函数对象创建出来的,如果变量对象已经办好了相同名字的属性,则替换它的值
-
变量声明:变量对象的一个属性,其属性名即为变量名,其值为undefined;如果变量名和已经声明的函数名或者函数的参数名,则不会影响已经存在的属性
-
(2)执行代码阶段,变量对象中的一些属性undefined值将会确定
-
这里需要说明一下:函数表达式不包含在变量对象之中
-
活动对象:当函数被调用的时候,一个特殊的对象–活动对象将会被创建。这个对象中包含形参和arguments对象。活动对象之后会作为函数上下文的变量对象来使用。换句话说,活动对象除了变量和函数声明之外,它还存储了形参和arguments对象。
1.9 ajax如何实现、readyState五中状态的含义
-
function createXMLHttpRequest() {
-
var xmlHttp;
-
// 适用于大多数浏览器,以及IE7和IE更高版本
-
try{
-
xmlHttp = new XMLHttpRequest();
-
} catch (e) {
-
// 适用于IE6
-
try {
-
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
-
} catch (e) {
-
// 适用于IE5.5,以及IE更早版本
-
try{
-
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
-
} catch (e){}
-
}
-
}
-
return xmlHttp;
-
};
-
1、get请求
-
xmlHttp.open("GET", "/ajax_get/?a=1", true); //第一个参数为请求方式,第二个参数为请求的服务器地址,第三个参数表示是否异步请求,默认不传值为true
-
xmlHttp.send(null); //get请求没有请求体数据,但是需要发送null,否则会引起火狐浏览器无法正常发送
-
2、post请求
-
xmlHttp.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”); //设置请求头,form表单会默认这个键值对不设定,Web服务器会忽略请求体的内容。
-
xmlHttp.send(“username=yuan&password=123”) //设置请求体数据
-
3、状态码和响应内容只有在状态4才能获取到
-
xmlHttp.onreadystatechange = function() {
-
if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
-
alert(xmlHttp.responseText);
-
}
-
};
-
//状态值
-
0:初始化未完成状态,只是创建了XMLHttpRequest对象,还未调用open()方法;
-
1:请求已开始,open()方法已调用,但还没调用send()方法;
-
2:请求发送完成状态,send()方法已调用;
-
3:开始读取服务器响应;
-
4:读取服务器响应结束。onreadystatechange事件只会在除0以外的状态下触发。
1.11 jsonp如何实现
-
function loadScript(url, func) {
-
var head = document.head || document.getElementByTagName('head')[0];
-
var script = document.createElement('script');
-
script.src = url;
-
script.onload = script.onreadystatechange = function() {
-
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
-
func();
-
script.onload = script.onreadystatechange = null;
-
}
-
};
-
head.insertBefore(script, 0);
-
}
-
window.baidu = {
-
sug: function(data) {
-
console.log(data);
-
}
-
}
-
loadScript('http://suggestion.baidu.com/su?wd=w', function() { console.log('loaded') });
1.12怎么处理跨域
-
1、通过jsonp跨域
-
2、CORS
-
主要工作是在服务端加上响应头res.header("Access-Control-Allow-Origin", "xxx"),只要响应头中包含了请求头(Origin),就可以实现跨域,相当于数据请求的决定权在于服务端是否同意,因此CORS对于代码的修改也只需修改服务端代码即可。
-
3、document.domain + iframe (只有在主域相同的时候才能使用该方法)
-
4、location.hash + iframe
-
原理是利用location.hash来进行传值。
-
假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息。
-
1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面
-
2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据
-
3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值
-
注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe
-
5、window.name + iframe
-
6、postMessage(HTML5中的XMLHttpRequest Level 2中的API)
-
7、web sockets (web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用))
1.13 restful的method解释
-
以前基本就用http的post和get。
-
restful就是让你把delete put patch这些method给用起来,而不是通过post加上参数action=delete来实现删除操作。
1.14 get和post的区别
-
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。 GET和POST还有一个重大区别,简单的说:GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
1.15 事件模型解释
-
javascript中有两种事件模型:DOM0,DOM2
-
1. DOM0级事件模型
-
DOM0级事件模型是早期的事件模型,所有的浏览器都是支持的,而且其实现也是比较简单。代码如下:
-
<p id = 'click'>click me</p>
-
<script>
-
document.getElementById('click').onclick = function(event){
-
alert(event.target);
-
}
-
</script>
-
这种事件模型就是直接在dom对象上注册事件名称,这段代码就是在p标签上注册了一个onclick事件,在这个事件函数内部输出点击的目标。而解除事件则更加简单,就是将null复制给事件函数,如下:
-
document.getElementById('click'_).onclick = null;
-
由此我们可以知道dom0中,一个dom对象只能注册一个同类型的函数,因为注册多个同类型的函数的话,就会发生覆盖,之前注册的函数就会无效。
-
2. DOM2级事件模型
-
2.1 事件捕获和事件冒泡(capture,bubble)
-
首先,IE8及以下是不支持这种事件模型的。假设我们点击了ID为inner的div,那么此时的事件流程就是,首先执行捕获阶段:document-html-body-div(outer)。然后执行冒泡阶段:div(inner)-div(outer)-body-html-document。
-
2.2 DOM2级的注册事件和解除事件
-
在DOM2级中使用attachEvent/addEventListener和removeEventListener来注册和解除事件(IE8及之前版本不支持)。这种函数较之之前的方法好处是一个dom对象可以注册多个相同类型的事件,不会发生事件的覆盖,会依次的执行各个事件函数。
-
addEventListener('事件名称','事件回调','捕获/冒泡')。第三个参数代表捕获还是冒泡,true代表捕获事件,false代表冒泡事件。
-
btn1Obj.attachEvent("onclick",method1); detachEvent(event,function);
-
假如同时有捕获和冒泡,事件捕获比事件冒泡先执行。
1.16 编写一个元素拖拽的插件
1.17 编写一个contextmenu的插件
1.18 编写web端cookie的设置和获取方法
-
//设置
-
document.cookie="userId=828; path=/;domain=cookieDomain;expires="+date.toGMTString();
-
document.cookie="str="+escape("I love ajax");
-
//获取
-
function getCookie(name){
-
var strCookie=document.cookie;
-
var arrCookie=strCookie.split("; ");
-
for(var i=0;i<arrCookie.length;i++){
-
var arr=arrCookie[i].split("=");
-
if(arr[0]==name)return arr[1];
-
}
-
return "";
-
}
-
//删除,设置过期
-
function deleteCookie(name){
-
var date=new Date();
-
date.setTime(date.getTime()-10000);
-
document.cookie=name+”=v; expires=”+date.toGMTString();
-
}
1.19 兼容ie6的水平垂直居中
1.20 兼容ie的事件封装
-
//事件处理兼容各种浏览器,采用能力检测方法,所谓能力检测,就是有能力就做,没有能力就不做
-
//定义一个处理事件的对象,兼容各种浏览器,dom2级事件处理和ie事件,如果这两个事件都不兼容,就采用dom0级处理
-
var eventUtil ={
-
addEvent:function(element,type,handler){
-
if (element.addEventListener) {
-
//非IE浏览器采用dom2级事件处理,type为事件类型如:click,handler为事件处理函数,false代表事件采用冒泡处理模型,如果是true代表 采用捕获型处理模型
-
//除了netbeans采用捕获型处理模型,其他都采用冒泡型处理模型
-
//如果是非IE浏览器添加事件为:addEventListener
-
element.addEventListener(type,handler,false);
-
}else if (element.attachEvent) {
-
//如果为IE浏览器,添加事件采用 attachEvent
-
element.attachEvent('on'+type,handler);
-
}else{
-
element['on'+type] = handler;
-
}
-
},
-
removeEvent:function(element,type,handler){
-
if (element.removeEventListener) {
-
//非IE浏览器采用dom2级事件处理,type为事件类型如:click,handler为事件处理函数,false代表事件采用冒泡处理模型,如果是true代表 采用捕获型处理模型
-
//除了netbeans采用捕获型处理模型,其他都采用冒泡型处理模型
-
//如果是非IE浏览器添加事件为:removeEventListener
-
element.removeEventListener(type,handler,false);
-
}else if (element.detachEvent) {
-
//如果为IE浏览器,添加事件采用 detachEvent
-
element.detachEvent('on'+type,handler);
-
}else{
-
//dom0级事件处理,如果删除事件采用赋值null
-
element['on'+type] = null;
-
}
-
},
-
getEvent:function(event){
-
//获取事件本身
-
return event?event:window.event;
-
},
-
getType:function(event){
-
//获取事件类型
-
return event.type;
-
},
-
getElement:function(event){
-
//获取事件作用元素
-
return event.target || event.srcElement;
-
},
-
preventDefault:function(event){
-
//阻止默认的事件行为
-
if(event.preventDefault){
-
event.preventDefault();
-
}else{
-
event.returnValue = false;
-
}
-
},
-
stopProPagation:function(event){
-
//停止事件冒泡
-
if(event.stopProPagation){
-
event.stopProPagation();
-
}else{
-
event.cancelBubble = true;
-
}
-
}
-
}
1.21 h5和原生android的优缺点
1.22 编写h5需要注意什么
-
1. 交互上,慎用向右滑动的操作方式。 原因:苹果手机上,向右滑动容易触发返回“上一级页面”效果。
-
2. 交互上,慎用横屏展示效果。 原因:体验上,需要用户设备开启屏幕旋转功能,才能正常观看,用户操作成本高。
对不同屏幕的手机,长宽比例不一,难以展示最佳的视觉效果。
-
3. 视觉上,功能按钮等,远离页面底部(大概128px,这个尺寸不是固定值)
-
4. 动画上,序列帧压缩小技巧,静态的画面,保存较高质量。中间运动的模糊状态,大胆的压低画面质量吧。 原因:压缩体积,运动状态就算有锯齿也不明显。
-
5. 重构上,视频无法自动播放,首次播放需要用户点击触发。
1.23 xss和crsf的原理以及怎么预防
-
1.XSS成因概括 :XSS其实就是Html的注入问题,攻击者的输入没有经过严格的控制进入了数据库,最终显示给来访的用户,导致可以在来访用户的浏览器里以浏览用户的身份执行Html代码,数据流程如下:攻击者的Html输入—>web程序—>进入数据库—>web程序—>用户浏览器。
-
解决:使用转义
-
2.CSRF:冒充用户之手(模拟发请求)
-
解决:令牌来防止 CSRF 有以下几点要注意:
-
a.虽然请求令牌原理和验证码有相似之处,但不应该像验证码一样,全局使用一个 Session Key。因为请求令牌的方法在理论上是可破解的,破解方式是解析来源页面的文本,获取令牌内容。如果全局使用一个 Session Key,那么危险系数会上升。原则上来说,每个页面的请求令牌都应该放在独立的 Session Key 中。我们在设计服务器端的时候,可以稍加封装,编写一个令牌工具包,将页面的标识作为 Session 中保存令牌的键。
-
b.在 ajax 技术应用较多的场合,因为很有请求是 JavaScript 发起的,使用静态的模版输出令牌值或多或少有些不方便。但无论如何,请不要提供直接获取令牌值的 API。这么做无疑是锁上了大门,却又把钥匙放在门口,让我们的请求令牌退化为同步令牌。
-
c.第一点说了请求令牌理论上是可破解的,所以非常重要的场合,应该考虑使用验证码(令牌的一种升级,目前来看破解难度极大),或者要求用户再次输入密码(亚马逊、淘宝的做法)。但这两种方式用户体验都不好,所以需要产品开发者权衡。
-
d.无论是普通的请求令牌还是验证码,服务器端验证过一定记得销毁。忘记销毁用过的令牌是个很低级但是杀伤力很大的错误。我们学校的选课系统就有这个问题,验证码用完并未销毁,故只要获取一次验证码图片,其中的验证码可以在多次请求中使用(只要不再次刷新验证码图片),一直用到。
1.24 css优先级
1.25 如何实现点击radio的文字描述控制radio的状态(通过label实现)
1.26 delegate如何实现
1.27 使用Promise封装简单Ajax方法
1.GET
-
function getJSON (url) {
-
return new Promise( (resolve, reject) => {
-
var xhr = new XMLHttpRequest()
-
xhr.open('GET', url, true)
-
xhr.onreadystatechange = function () {
-
if (this.readyState === 4) {
-
if (this.status === 200) {
-
resolve(this.responseText, this)
-
} else {
-
var resJson = { code: this.status, response: this.response }
-
reject(resJson, this)
-
}
-
}
-
}
-
xhr.send()
-
})
-
}
2.POST
-
function postJSON(url, data) {
-
return new Promise( (resolve, reject) => {
-
var xhr = new XMLHttpRequest()
-
xhr.open("POST", url, true)
-
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
-
xhr.onreadystatechange = function () {
-
if (this.readyState === 4) {
-
if (this.status === 200) {
-
resolve(JSON.parse(this.responseText), this)
-
} else {
-
var resJson = { code: this.status, response: this.response }
-
reject(resJson, this)
-
}
-
}
-
}
-
xhr.send(JSON.stringify(data))
-
})
-
}
2.框架原理
2.1 angularjs
2.1.1 angular的directive怎么写
2.1.2 angular的脏检查(双向绑定)是如何实现的
2.1.3 依赖注入如何实现
2.1.4 scope如何实现
2.1.5 $parse模块如何实现(主要自己写了一个类似的库)
2.2 react
2.2.1 react在setState后发生了什么(直接说了setState源码)
-
在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
-
setState从来不负责更新操作。它的工作只是把state,和callback放进序列,并且把要更新的组件放到dirtyComponents序列
还记得吗?我们还在ReactDefalutBatchingStragy的事务中,perform执行完了,还要执行close。 真正执行更新方法的是close里面的flushBatchedUpdates。
2.2.2 redux解释
2.2.3 对react有什么了解(直接说了react中虚拟dom内部表示,mount过程源码和同步过程源码)
2.2.4 jsBridge
2.2.5 如何说服对方使用jsBridge
2.2.6 diff算法
-
传统 diff 算法的复杂度为 O(n^3),显然这是无法满足性能要求的。React 通过制定大胆的策略,将 O(n^3) 复杂度的问题转换成 O(n) 复杂度的问题。
-
diff 策略:
-
tree diff Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计。
-
component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。
-
element diff 对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。
2.3 requirejs
2.3.1 amd和cmd区别,怎么了解到这些区别的,是否是去看了规范
-
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
-
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
-
相同之处
-
RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。
-
不同之处
-
两者的主要区别如下:
-
1.定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
-
2.遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
-
3.推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。
-
4.对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。
-
5.插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。
2.3.2 requirejs那些经常用的方法,然后对其进行解释
2.4 weex
2.4.1 weex实现大致原理(只写过demo,面试管很好没有难为我,只问了这一个问题)
3.http协议
3.1 accept是什么,怎么用
-
1.Accept属于请求头, Content-Type属于实体头。
-
2.Accept代表发送端(客户端)希望接受的数据类型。
-
比如:Accept:text/xml; 代表客户端希望接受的数据类型是xml类型
3.2 http协议状态码,302和303的区别
3.4 前端缓存如何实现、etag如何实现、etag和cache-control的max-age的优先级哪个比较高以及为什么、cache-control和expire优先级哪个比较高以及为什么
-
1)Expires是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2016 23:55:55 GMT,
-
2)Cache-Control描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较Expires,Cache-Control的缓存管理更有效,安全一些。
-
3)Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。
-
Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
-
If-Modified-Since:当资源过期时(强缓存失效),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
-
4)Etag/If-None-Match:Etag/If-None-Match也要配合Cache-Control使用。
-
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
-
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
4.node
4.1 Buffer模块是干什么的
-
在 ECMAScript 2015 (ES6) 引入 TypedArray 之前,JavaScript 语言没有读取或操作二进制数据流的机制。 Buffer 类被引入作为 Node.js API 的一部分,使其可以在 TCP 流或文件系统操作等场景中处理二进制数据流。
4.2 Stream是什么,使用的两种模式
-
流(stream)在 Node.js 中是处理流数据的抽象接口(abstract interface)。 stream 模块提供了基础的 API 。使用这些 API 可以很容易地来构建实现流接口的对象。
-
在 flowing 模式下, 可读流自动从系统底层读取数据,并通过 EventEmitter 接口的事件尽快将数据提供给应用。
-
在 paused 模式下,必须显式调用 stream.read() 方法来从流中读取数据片段。
4.3 http模块如何将异步处理方式实现成同步处理方式,具体解析请参考http模块如何将异步处理转成同步处理
-
const http = require("http");
-
const net = require("net");
-
// 保存请求的队列,每个元素都是一个socket
-
let watingQueue = [];
-
// 当前处理的请求
-
let curtSocket = null;
-
let count = 0;
-
// 建立一个http服务器
-
let httpServer = http.createServer(function (req, res) {
-
// 延迟一秒中回复
-
setTimeout(function () {
-
res.end(`request: ${++count}`, "utf8");
-
}, 1000);
-
res.on("finish", function () {
-
curtSocket = null;
-
// 一个请求结束了,处理下一个请求
-
dealRequest();
-
});
-
});
-
// 建立一个tcp的服务器(http协议是建立在tcp协议上的)
-
net.createServer(function (socket) {
-
// 将请求压入列队
-
enqueueSocket(socket);
-
// 处理请求(如果现在真在处理的请求,不做任何处理)
-
dealRequest();
-
}).listen(4000);
-
function enqueueSocket (socket) {
-
watingQueue.push(socket);
-
}
-
function dealRequest () {
-
if (curtSocket != null || watingQueue.length <= 0) {
-
return;
-
}
-
curtSocket = watingQueue.shift();
-
httpServer.emit("connection", curtSocket);
-
}
5.其他问题
5.1 utf8和gbk的区别
-
UTF-8 (8-bit Unicode Transformation Format) 是一种针对Unicode的可变长度字符编码,又称万国码,它包含全世界所有国家需要用到的字符,是国际编码,通用性强,是用以解决国际上字符的一种多字节编码。由Ken Thompson于1992年创建。UTF-8用1到4个字节编码UNICODE字符,它对英文使用8位/8Bit(即1个字节/1Byte),中文使用24位/24Bit(3个字节/3Byte)来编码。用在网页上可以同一页面显示中文简体繁体及其它语言(如日文,韩文)。
-
GBK (Chinese Internal Code Specification) 是汉字编码标准之一,全称《汉字内码扩展规范》,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订,国家技术监督局标准化司、电子工业部科技与质量监督司1995年12月15日联合以技监标函1995 229号文件的形式,将它确定为技术规范指导性文件。
GBK是国家标准GB2312基础上扩容后兼容GB2312的标准(GB2312共收录了7445个字符,包括6763个汉字和682个其它符号;GBK共收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字)。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示(注意,GB系列编码是利用了字节中的最高位和ASCII编码区分的,可以和ASCII码混用。所以全角模式下英文是2字节,半角模式英文还是1字节)。为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBD大。
-
简单概况就是:
-
UTF-8英文1字节中文3字节,在编码效率和编码安全性之间做了平衡,适合网络传输,是理想的中文编码方式.
-
GBK英文1字节(半角1字节,全角2字节),中文2字节,GBK的范围比GB2312广,GBK兼容GB2312。
转载于:https://www.cnblogs.com/ssen/p/9774094.html