共计 10443 个字符,预计需要花费 27 分钟才能阅读完成。
渲染引擎什么状况下才会为特定的节点创立新的图层
层叠上下文
是 HTML 元素的三维概念,这些 HTML 元素在一条假想的绝对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延长,HTML 元素根据其本身属性依照优先级程序占用层叠上下文的空间。
- 领有层叠上下文属性的元素会被晋升为独自的一层。
领有层叠上下文属性:
- 根元素 (HTML),
- z-index 值不为 “auto” 的 相对 / 绝对定位元素,
- position, 固定(fixed)/ 沾滞(sticky)定位(沾滞定位适配所有挪动设施上的浏览器,但老的桌面浏览器不反对)
- z-index 值不为 “auto” 的 flex 子项 (flex item),即:父元素 display: flex|inline-flex,
- z-index 值不为 ”auto” 的 grid 子项,即:父元素 display:grid
- opacity 属性值小于 1 的元素(参考 the specification for opacity),
- transform 属性值不为 “none” 的元素,
- mix-blend-mode 属性值不为 “normal” 的元素,
- filter 值不为 ”none” 的元素,
- perspective 值不为 ”none” 的元素,
- clip-path 值不为 ”none” 的元素
- mask / mask-image / mask-border 不为 ”none” 的元素
- isolation 属性被设置为 “isolate” 的元素
- 在 will-change 中指定了任意 CSS 属性(参考 这篇文章)
- -webkit-overflow-scrolling 属性被设置 “touch” 的元素
- contain 属性值为 ”layout”,”paint”,或者综合值比方 ”strict”,”content”
- 须要剪裁(clip)的中央也会被创立为图层。
这里的剪裁指的是,如果咱们把 div 的大小限定为 200 200 像素,而 div 外面的文字内容比拟多,文字所显示的区域必定会超出 200 200 的面积,这时候就产生了剪裁,渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域。呈现这种裁剪状况的时候,渲染引擎会为文字局部独自创立一个层,如果呈现滚动条,滚动条也会被晋升为独自的层。
Nginx 的概念及其工作原理
Nginx 是一款轻量级的 Web 服务器,也能够用于反向代理、负载平衡和 HTTP 缓存等。Nginx 应用异步事件驱动的办法来解决申请,是一款面向性能设计的 HTTP 服务器。
传统的 Web 服务器如 Apache 是 process-based 模型的,而 Nginx 是基于 event-driven 模型的。正是这个次要的区别带给了 Nginx 在性能上的劣势。
Nginx 架构的最顶层是一个 master process,这个 master process 用于产生其余的 worker process,这一点和 Apache 十分像,然而 Nginx 的 worker process 能够同时解决大量的 HTTP 申请,而每个 Apache process 只能解决一个。
代码输入后果
async function async1() {console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {console.log("async2");
}
console.log("script start");
setTimeout(function() {console.log("setTimeout");
}, 0);
async1();
new Promise(resolve => {console.log("promise1");
resolve();}).then(function() {console.log("promise2");
});
console.log('script end')
输入后果如下:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
代码执行过程如下:
- 结尾定义了 async1 和 async2 两个函数,然而并未执行,执行 script 中的代码,所以打印出 script start;
- 遇到定时器 Settimeout,它是一个宏工作,将其退出到宏工作队列;
- 之后执行函数 async1,首先打印出 async1 start;
- 遇到 await,执行 async2,打印出 async2,并阻断前面代码的执行,将前面的代码退出到微工作队列;
- 而后跳出 async1 和 async2,遇到 Promise,打印出 promise1;
- 遇到 resolve,将其退出到微工作队列,而后执行前面的 script 代码,打印出 script end;
- 之后就该执行微工作队列了,首先打印出 async1 end,而后打印出 promise2;
- 执行完微工作队列,就开始执行宏工作队列中的定时器,打印出 setTimeout。
如何进攻 CSRF 攻打?
CSRF 攻打能够应用以下办法来防护:
- 进行同源检测,服务器依据 http 申请头中 origin 或者 referer 信息来判断申请是否为容许拜访的站点,从而对申请进行过滤。当 origin 或者 referer 信息都不存在的时候,间接阻止申请。这种形式的毛病是有些状况下 referer 能够被伪造,同时还会把搜索引擎的链接也给屏蔽了。所以个别网站会容许搜索引擎的页面申请,然而相应的页面申请这种申请形式也可能被攻击者给利用。(Referer 字段会通知服务器该网页是从哪个页面链接过去的)
- 应用 CSRF Token 进行验证,服务器向用户返回一个随机数 Token,当网站再次发动申请时,在申请参数中退出服务器端返回的 token,而后服务器对这个 token 进行验证。这种办法解决了应用 cookie 繁多验证形式时,可能会被冒用的问题,然而这种办法存在一个毛病就是,咱们须要给网站中的所有申请都增加上这个 token,操作比拟繁琐。还有一个问题是个别不会只有一台网站服务器,如果申请通过负载平衡转移到了其余的服务器,然而这个服务器的 session 中没有保留这个 token 的话,就没有方法验证了。这种状况能够通过扭转 token 的构建形式来解决。
- 对 Cookie 进行双重验证,服务器在用户拜访网站页面时,向申请域名注入一个 Cookie,内容为随机字符串,而后当用户再次向服务器发送申请的时候,从 cookie 中取出这个字符串,增加到 URL 参数中,而后服务器通过对 cookie 中的数据和参数中的数据进行比拟,来进行验证。应用这种形式是利用了攻击者只能利用 cookie,然而不能拜访获取 cookie 的特点。并且这种办法比 CSRF Token 的办法更加不便,并且不波及到分布式拜访的问题。这种办法的毛病是如果网站存在 XSS 破绽的,那么这种形式会生效。同时这种形式不能做到子域名的隔离。
- 在设置 cookie 属性的时候设置 Samesite,限度 cookie 不能作为被第三方应用,从而能够防止被攻击者利用。Samesite 一共有两种模式,一种是严格模式,在严格模式下 cookie 在任何状况下都不可能作为第三方 Cookie 应用,在宽松模式下,cookie 能够被申请是 GET 申请,且会产生页面跳转的申请所应用。
前端贮存的⽅式有哪些?
- cookies:在 HTML5 规范前本地贮存的次要⽅式,长处是兼容性好,申请头⾃带 cookie ⽅便,毛病是⼤⼩只有 4k,⾃动申请头加⼊ cookie 节约流量,每个 domain 限度 20 个 cookie,使⽤起来麻烦,须要⾃⾏封装;
- localStorage:HTML5 加⼊的以键值对 (Key-Value) 为规范的⽅式,长处是操作⽅便,永久性贮存(除⾮⼿动删除),⼤⼩为 5M,兼容 IE8+;
- sessionStorage:与 localStorage 根本相似,区别是 sessionStorage 当⻚⾯敞开后会被清理,⽽且与 cookie、localStorage 不同,他不能在所有同源窗⼝中共享,是会话级别的贮存⽅式;
- Web SQL:2010 年被 W3C 废除的本地数据库数据存储⽅案,然而支流浏览器(⽕狐除外)都曾经有了相干的实现,web sql 相似于 SQLite,是真正意义上的关系型数据库,⽤ sql 进⾏操作,当咱们⽤ JavaScript 时要进⾏转换,较为繁琐;
- IndexedDB:是被正式纳⼊ HTML5 规范的数据库贮存⽅案,它是 NoSQL 数据库,⽤键值对进⾏贮存,能够进⾏疾速读取操作,⾮常适宜 web 场景,同时⽤ JavaScript 进⾏操作会⾮常便。
代码输入后果
console.log(1);
setTimeout(() => {console.log(2);
Promise.resolve().then(() => {console.log(3)
});
});
new Promise((resolve, reject) => {console.log(4)
resolve(5)
}).then((data) => {console.log(data);
})
setTimeout(() => {console.log(6);
})
console.log(7);
代码输入后果如下:
1
4
7
5
2
3
6
代码执行过程如下:
- 首先执行 scrip 代码,打印出 1;
- 遇到第一个定时器 setTimeout,将其退出到宏工作队列;
- 遇到 Promise,执行外面的同步代码,打印出 4,遇到 resolve,将其退出到微工作队列;
- 遇到第二个定时器 setTimeout,将其退出到红工作队列;
- 执行 script 代码,打印出 7,至此第一轮执行实现;
- 指定微工作队列中的代码,打印出 resolve 的后果:5;
- 执行宏工作中的第一个定时器 setTimeout,首先打印出 2,而后遇到 Promise.resolve().then(),将其退出到微工作队列;
- 执行完这个宏工作,就开始执行微工作队列,打印出 3;
- 继续执行宏工作队列中的第二个定时器,打印出 6。
网络劫持有哪几种,如何防备?
⽹络劫持分为两种:
(1)DNS 劫持: (输⼊京东被强制跳转到淘宝这就属于 dns 劫持)
- DNS 强制解析: 通过批改运营商的本地 DNS 记录,来疏导⽤户流量到缓存服务器
- 302 跳转的⽅式: 通过监控⽹络出⼝的流量,分析判断哪些内容是能够进⾏劫持解决的, 再对劫持的内存发动 302 跳转的回复,疏导⽤户获取内容
(2)HTTP 劫持: (拜访⾕歌然而⼀直有贪玩蓝⽉的⼴告), 因为 http 明⽂传输, 运营商会批改你的 http 响应内容(即加⼴告)
DNS 劫持因为涉嫌守法,曾经被监管起来,当初很少会有 DNS 劫持,⽽ http 劫持仍然⾮常盛⾏,最无效的方法就是全站 HTTPS,将 HTTP 加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容。
死锁产生的起因?如果解决死锁的问题?
所谓死锁,是指多个过程在运行过程中因抢夺资源而造成的一种僵局,当过程处于这种僵持状态时,若无外力作用,它们都将无奈再向前推动。
零碎中的资源能够分为两类:
- 可剥夺资源,是指某过程在取得这类资源后,该资源能够再被其余过程或零碎剥夺,CPU 和主存均属于可剥夺性资源;
- 不可剥夺资源,当零碎把这类资源分配给某过程后,再不能强行发出,只能在过程用完后自行开释,如磁带机、打印机等。
产生死锁的起因:
(1)竞争资源
- 产生死锁中的竞争资源之一指的是 竞争不可剥夺资源(例如:零碎中只有一台打印机,可供过程 P1 应用,假设 P1 已占用了打印机,若 P2 持续要求打印机打印将阻塞)
- 产生死锁中的竞争资源另外一种资源指的是 竞争长期资源(长期资源包含硬件中断、信号、音讯、缓冲区内的音讯等),通常音讯通信程序进行不当,则会产生死锁
(2)过程间推动程序非法
若 P1 放弃了资源 R1,P2 放弃了资源 R2,零碎处于不平安状态,因为这两个过程再向前推动,便可能产生死锁。例如,当 P1 运行到 P1:Request(R2)时,将因 R2 已被 P2 占用而阻塞;当 P2 运行到 P2:Request(R1)时,也将因 R1 已被 P1 占用而阻塞,于是产生过程死锁
产生死锁的必要条件:
- 互斥条件:过程要求对所调配的资源进行排它性管制,即在一段时间内某资源仅为一过程所占用。
- 申请和放弃条件:当过程因申请资源而阻塞时,对已取得的资源放弃不放。
- 不剥夺条件:过程已取得的资源在未应用完之前,不能剥夺,只能在应用完时由本人开释。
- 环路期待条件:在产生死锁时,必然存在一个过程——资源的环形链。
预防死锁的办法:
- 资源一次性调配:一次性调配所有资源,这样就不会再有申请了(毁坏申请条件)
- 只有有一个资源得不到调配,也不给这个过程调配其余的资源(毁坏请放弃条件)
- 可剥夺资源:即当某过程取得了局部资源,但得不到其它资源,则开释已占有的资源(毁坏不可剥夺条件)
- 资源有序调配法:零碎给每类资源赋予一个编号,每一个过程按编号递增的程序申请资源,开释则相同(毁坏环路期待条件)
代码输入后果
var length = 10;
function fn() {console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {fn();
arguments[0]();}
};
obj.method(fn, 1);
输入后果:10 2
解析:
- 第一次执行 fn(),this 指向 window 对象,输入 10。
- 第二次执行 arguments[0],相当于 arguments 调用办法,this 指向 arguments,而这里传了两个参数,故输入 arguments 长度为 2。
参考:前端进阶面试题具体解答
箭头函数和一般函数有什么区别?
(1)箭头函数比一般函数更加简洁
如果没有参数,就间接写一个空括号即可
如果只有一个参数,能够省去参数括号
如果有多个参数,用逗号宰割
如果函数体的返回值只有一句,能够省略大括号
如果函数体不须要返回值,且只有一句话,能够给这个语句后面加一个 void 关键字。最罕用的就是调用一个函数:let fn = () => void doesNotReturn()
(2) 箭头函数没有本人的 this
箭头函数不会创立本人的 this, 所以它没有本人的 this, 它只会在本人作用域的上一层继承 this。所以箭头函数中的 this 的指向在它在定义时一家确定了,之后不会扭转。(3)箭头函数继承来的 this 指向永远不会扭转
(4) call()、apply()、bind()等办法不能扭转箭头函数中的 this 指向
(5) 箭头函数不能作为构造函数应用
(6) 箭头函数没有本人的 arguments
(7) 箭头函数没有 prototype
(8) 箭头函数不能用作 Generator 函数, 不能应用 yeild 关键字
说一下类组件和函数组件的区别?
1. 语法上的区别:函数式组件是一个纯函数,它是须要承受 props 参数并且返回一个 React 元素就能够了。类组件是须要继承 React.Component 的,而且 class 组件须要创立 render 并且返回 React 元素,语法上来讲更简单。2. 调用形式
函数式组件能够间接调用,返回一个新的 React 元素;类组件在调用时是须要创立一个实例的,而后通过调用实例里的 render 办法来返回一个 React 元素。3. 状态治理
函数式组件没有状态治理,类组件有状态治理。4. 应用场景
类组件没有具体的要求。函数式组件个别是用在大型项目中来宰割大组件(函数式组件不必创立实例,所有更高效),个别状况下能用函数式组件就不必类组件,晋升效率。
代码输入后果
var a=3;
function c(){alert(a);
}
(function(){
var a=4;
c();})();
js 中变量的作用域链与定义时的环境无关,与执行时无关。执行环境只会扭转 this、传递的参数、全局变量等
浏览器的渲染过程
浏览器渲染次要有以下步骤:
- 首先解析收到的文档,依据文档定义构建一棵 DOM 树,DOM 树是由 DOM 元素及属性节点组成的。
- 而后对 CSS 进行解析,生成 CSSOM 规定树。
- 依据 DOM 树和 CSSOM 规定树构建渲染树。渲染树的节点被称为渲染对象,渲染对象是一个蕴含有色彩和大小等属性的矩形,渲染对象和 DOM 元素绝对应,但这种对应关系不是一对一的,不可见的 DOM 元素不会被插入渲染树。还有一些 DOM 元素对应几个可见对象,它们个别是一些具备简单构造的元素,无奈用一个矩形来形容。
- 当渲染对象被创立并增加到树中,它们并没有地位和大小,所以当浏览器生成渲染树当前,就会依据渲染树来进行布局(也能够叫做回流)。这一阶段浏览器要做的事件是要弄清楚各个节点在页面中的确切地位和大小。通常这一行为也被称为“主动重排”。
- 布局阶段完结后是绘制阶段,遍历渲染树并调用渲染对象的 paint 办法将它们的内容显示在屏幕上,绘制应用 UI 根底组件。
大抵过程如图所示:
留神: 这个过程是逐渐实现的,为了更好的用户体验,渲染引擎将会尽可能早的将内容出现到屏幕上,并不会等到所有的 html 都解析实现之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
代码输入后果
async function async1 () {console.log('async1 start');
await new Promise(resolve => {console.log('promise1')
resolve('promise1 resolve')
}).then(res => console.log(res))
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
这里是对下面一题进行了革新,加上了 resolve。
输入后果如下:
script start
async1 start
promise1
script end
promise1 resolve
async1 success
async1 end
对浏览器的了解
浏览器的次要性能是将用户抉择的 web 资源出现进去,它须要从服务器申请资源,并将其显示在浏览器窗口中,资源的格局通常是 HTML,也包含 PDF、image 及其他格局。用户用 URI(Uniform Resource Identifier 对立资源标识符)来指定所申请资源的地位。
HTML 和 CSS 标准中规定了浏览器解释 html 文档的形式,由 W3C 组织对这些标准进行保护,W3C 是负责制订 web 规范的组织。然而浏览器厂商纷纷开发本人的扩大,对标准的遵循并不欠缺,这为 web 开发者带来了重大的兼容性问题。
浏览器能够分为两局部,shell 和 内核。其中 shell 的品种绝对比拟多,内核则比拟少。也有一些浏览器并不辨别外壳和内核。从 Mozilla 将 Gecko 独立进去后,才有了外壳和内核的明确划分。
- shell 是指浏览器的外壳:例如菜单,工具栏等。次要是提供给用户界面操作,参数设置等等。它是调用内核来实现各种性能的。
- 内核是浏览器的外围。内核是基于标记语言显示内容的程序或模块。
函数节流
触发高频事件,且 N 秒内只执行一次。
简略版:应用工夫戳来实现,立刻执行一次,而后每 N 秒执行一次。
function throttle(func, wait) {
var context, args;
var previous = 0;
return function() {var now = +new Date();
context = this;
args = arguments;
if (now - previous > wait) {func.apply(context, args);
previous = now;
}
}
}
最终版:反对勾销节流;另外通过传入第三个参数,options.leading 来示意是否能够立刻执行一次,opitons.trailing 示意完结调用的时候是否还要执行一次,默认都是 true。
留神设置的时候不能同时将 leading 或 trailing 设置为 false。
function throttle(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {var now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {if (timeout) {clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {timeout = setTimeout(later, remaining);
}
};
throttled.cancel = function() {clearTimeout(timeout);
previous = 0;
timeout = null;
}
return throttled;
}
节流的应用就不拿代码举例了,参考防抖的写就行。
有哪些可能引起前端平安的问题?
- 跨站脚本 (Cross-Site Scripting, XSS): ⼀种代码注⼊⽅式, 为了与 CSS 辨别所以被称作 XSS。晚期常⻅于⽹络论坛, 起因是⽹站没有对⽤户的输⼊进⾏严格的限度, 使得攻击者能够将脚本上传到帖⼦让其余⼈浏览到有歹意脚本的⻚⾯, 其注⼊⽅式很简略包含但不限于 JavaScript / CSS / Flash 等;
- iframe 的滥⽤: iframe 中的内容是由第三⽅来提供的,默认状况下他们不受管制,他们能够在 iframe 中运⾏ JavaScirpt 脚本、Flash 插件、弹出对话框等等,这可能会毁坏前端⽤户体验;
- 跨站点申请伪造(Cross-Site Request Forgeries,CSRF): 指攻击者通过设置好的陷阱,强制对已实现认证的⽤户进⾏⾮预期的个⼈信息或设定信息等某些状态更新,属于被动攻打
- 歹意第三⽅库: ⽆论是后端服务器应⽤还是前端应⽤开发,绝⼤少数时候都是在借助开发框架和各种类库进⾏疾速开发,⼀旦第三⽅库被植⼊恶意代码很容易引起平安问题。
类数组转化为数组的办法
题目形容: 类数组领有 length 属性 能够应用下标来拜访元素 然而不能应用数组的办法 如何把类数组转化为数组?
实现代码如下:
const arrayLike=document.querySelectorAll('div')
// 1. 扩大运算符
[...arrayLike]
// 2.Array.from
Array.from(arrayLike)
// 3.Array.prototype.slice
Array.prototype.slice.call(arrayLike)
// 4.Array.apply
Array.apply(null, arrayLike)
// 5.Array.prototype.concat
Array.prototype.concat.apply([], arrayLike)
PWA 应用过吗?serviceWorker 的应用原理是啥?
渐进式网络应用(PWA)
是谷歌在 2015 年底提出的概念。基本上算是 web 应用程序,但在外观和感觉上与 原生 app
相似。反对 PWA
的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。
Service Worker
是浏览器在后盾独立于网页运行的脚本,它关上了通向不须要网页或用户交互的性能的大门。当初,它们已包含如推送告诉和后盾同步等性能。未来,Service Worker
将会反对如定期同步或天文围栏等其余性能。本教程探讨的外围性能是拦挡和解决网络申请,包含通过程序来治理缓存中的响应。
Cookie、LocalStorage、SessionStorage 区别
浏览器端罕用的存储技术是 cookie、localStorage 和 sessionStorage。
- cookie: 其实最开始是服务器端用于记录用户状态的一种形式,由服务器设置,在客户端存储,而后每次发动同源申请时,发送给服务器端。cookie 最多能存储 4 k 数据,它的生存工夫由 expires 属性指定,并且 cookie 只能被同源的页面访问共享。
- sessionStorage: html5 提供的一种浏览器本地存储的办法,它借鉴了服务器端 session 的概念,代表的是一次会话中所保留的数据。它个别可能存储 5M 或者更大的数据,它在以后窗口敞开后就生效了,并且 sessionStorage 只能被同一个窗口的同源页面所访问共享。
- localStorage: html5 提供的一种浏览器本地存储的办法,它个别也可能存储 5M 或者更大的数据。它和 sessionStorage 不同的是,除非手动删除它,否则它不会生效,并且 localStorage 也只能被同源页面所访问共享。
下面几种形式都是存储大量数据的时候的存储形式,当须要在本地存储大量数据的时候,咱们能够应用浏览器的 indexDB 这是浏览器提供的一种本地的数据库存储机制。它不是关系型数据库,它外部采纳对象仓库的模式存储数据,它更靠近 NoSQL 数据库。