CDN的原理
CDN和DNS有着密不可分的联系,先来看一下DNS的解析域名过程,在浏览器输入的解析过程如下:
(1) 检查浏览器缓存
(2)检查操作系统缓存,常见的如hosts文件
(3)检查路由器缓存
(4)如果前几步都没没找到,会向ISP(网络服务提供商)的LDNS服务器查询
(5)如果LDNS服务器没找到,会向根域名服务器(Root Server)请求解析,分为以下几步:
- 根服务器返回顶级域名(TLD)服务器如
.com
,.cn
,.org
等的地址,该例子中会返回.com
的地址 - 接着向顶级域名服务器发送请求,然后会返回次级域名(SLD)服务器的地址,本例子会返回
.test
的地址 - 接着向次级域名服务器发送请求,然后会返回通过域名查询到的目标IP,本例子会返回
www.test.com
的地址 - Local DNS Server会缓存结果,并返回给用户,缓存在系统中
- 浏览器通过DNS对域名进行解析(就是上面的DNS解析过程),依次得到此域名对应的IP地址
- 浏览器根据得到的IP地址,向域名的服务主机发送数据请求
- 服务器向浏览器返回响应数据
- 对于点击的数据的URL,经过本地DNS系统的解析,发现该URL对应的是一个CDN专用的DNS服务器,DNS系统就会将域名解析权交给CNAME指向的CDN专用的DNS服务器。
- CND专用DNS服务器将CND的全局负载均衡设备IP地址返回给用户
- 用户向CDN的全局负载均衡设备发起数据请求
- CDN的全局负载均衡设备根据用户的IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求
- 区域负载均衡设备选择一台合适的缓存服务器来提供服务,将该缓存服务器的IP地址返回给全局负载均衡设备
- 全局负载均衡设备把服务器的IP地址返回给用户
- 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送至用户终端。
CNAME(意为:别名):在域名解析中,实际上解析出来的指定域名对应的IP地址,或者该域名的一个CNAME,然后再根据这个CNAME来查找对应的IP地址。
Object.is 实现
题目描述:
Object.is不会转换被比较的两个值的类型,这点和===更为相似,他们之间也存在一些区别。
1. NaN在===中是不相等的,而在Object.is中是相等的
2. +0和-0在===中是相等的,而在Object.is中是不相等的
实现代码如下:
Object.is = function (x, y) {
if (x === y) {
// 当前情况下,只有一种情况是特殊的,即 +0 -0
// 如果 x !== 0,则返回true
// 如果 x === 0,则需要判断+0和-0,则可以直接使用 1/+0 === Infinity 和 1/-0 === -Infinity来进行判断
return x !== 0 || 1 / x === 1 / y;
}// x !== y 的情况下,只需要判断是否为NaN,如果x!==x,则说明x是NaN,同理y也一样
// x和y同时为NaN时,返回true
return x !== x && y !== y;
};
Promise.all和Promise.race的区别的使用场景
(1)Promise.all
Promise.all
可以将多个Promise
实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。Promise.all中传入的是数组,返回的也是是数组,并且会将进行映射,传入的promise对象返回的值是按照顺序在数组中排列的,但是注意的是他们执行的顺序并不是按照顺序的,除非可迭代对象为空。
需要注意,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,这样当遇到发送多个请求并根据请求顺序获取和使用数据的场景,就可以使用Promise.all来解决。
(2)Promise.race
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。当要做一件事,超过多长时间就不做了,可以用这个方法来解决:
Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})
代码输出结果
var F = function() {};
Object.prototype.a = function() {
console.log('a');
};
Function.prototype.b = function() {
console.log('b');
}
var f = new F();
f.a();
f.b();
F.a();
F.b()
输出结果:
a
Uncaught TypeError: f.b is not a function
a
b
解析:
- f 并不是 Function 的实例,因为它本来就不是构造函数,调用的是 Function 原型链上的相关属性和方法,只能访问到 Object 原型链。所以 f.a() 输出 a ,而 f.b() 就报错了。
- F 是个构造函数,而 F 是构造函数 Function 的一个实例。因为 F instanceof Object === true,F instanceof Function === true,由此可以得出结论:F 是 Object 和 Function 两个的实例,即 F 能访问到 a, 也能访问到 b。所以 F.a() 输出 a ,F.b() 输出 b。
function typeOf(obj) {
-let res = Object.prototype.toString.call(obj).split(' ')[1]
-res = res.substring(0, res.length - 1).toLowerCase()
-return res
// 更好的写法
+return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
typeOf([])// 'array'
typeOf({})// 'object'
typeOf(new Date)// 'date'
Vue路由守卫有哪些,怎么设置,使用场景等
常用的两个路由守卫:router.beforeEach 和 router.afterEach每个守卫方法接收三个参数:to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。
判断是否登录,是否拿到对应的路由权限等等。
为什么需要浏览器缓存?
对于浏览器的缓存,主要针对的是前端的静态资源,最好的效果就是,在发起请求之后,拉取相应的静态资源,并保存在本地。如果服务器的静态资源没有更新,那么在下次请求的时候,就直接从本地读取即可,如果服务器的静态资源已经更新,那么我们再次请求的时候,就到服务器拉取新的资源,并保存在本地。这样就大大的减少了请求的次数,提高了网站的性能。这就要用到浏览器的缓存策略了。
所谓的浏览器缓存指的是浏览器将用户请求过的静态资源,存储到电脑本地磁盘中,当浏览器再次访问时,就可以直接从本地加载,不需要再去服务端请求了。
使用浏览器缓存,有以下优点:
- 减少了服务器的负担,提高了网站的性能
- 加快了客户端网页的加载速度
- 减少了多余网络数据传输
浅拷贝:只考虑对象类型。
function shallowCopy(obj) {
if (typeof obj !== 'object') returnlet newObj = obj instanceof Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key]
}
}
return newObj
}
简单版深拷贝:只考虑普通对象属性,不考虑内置对象和函数。
function deepClone(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
}
}
return newObj;
}
复杂版深克隆:基于简单版的基础上,还考虑了内置对象比如 Date、RegExp 等对象和函数以及解决了循环引用的问题。
const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;
function deepClone(target, map = new WeakMap()) {
if (map.get(target)) {
return target;
}
// 获取当前值的构造函数:获取它的类型
let constructor = target.constructor;
// 检测当前对象target是否与正则、日期格式对象匹配
if (/^(RegExp|Date)$/i.test(constructor.name)) {
// 创建一个新的特殊对象(正则类/日期类)的实例
return new constructor(target);
}
if (isObject(target)) {
map.set(target, true);
// 为循环引用的对象做标记
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = deepClone(target[prop], map);
}
}
return cloneTarget;
} else {
return target;
}
}
label 的作用是什么?如何使用?
label标签来定义表单控件的关系:当用户选择label标签时,浏览器会自动将焦点转到和label标签相关的表单控件上。
- 使用方法1:
- 使用方法2:
什么是 JavaScript 中的包装类型?
在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:
const a = "abc";
a.length;
// 3
a.toUpperCase();
// "ABC"
在访问
'abc'.length
时,JavaScript 将'abc'
在后台转换成String('abc')
,然后再访问其length
属性。JavaScript也可以使用
Object
函数显式地将基本类型转换为包装类型:var a = 'abc'
Object(a) // String {"abc"}
也可以使用
valueOf
方法将包装类型倒转成基本类型:var a = 'abc'
var b = Object(a)
var c = b.valueOf() // 'abc'
看看如下代码会打印出什么:
var a = new Boolean( false );
if (!a) {
console.log( "Oops" );
// never runs
}
答案是什么都不会打印,因为虽然包裹的基本类型是
false
,但是false
被包裹成包装类型后就成了对象,所以其非值为false
,所以循环体中的内容不会运行。setInterval 模拟 setTimeout
描述:使用
setInterval
模拟实现setTimeout
的功能。思路:
setTimeout
的特性是在指定的时间内只执行一次,我们只要在setInterval
内部执行 callback
之后,把定时器关掉即可。实现:
const mySetTimeout = (fn, time) => {
let timer = null;
timer = setInterval(() => {
// 关闭定时器,保证只执行一次fn,也就达到了setTimeout的效果了
clearInterval(timer);
fn();
}, time);
// 返回用于关闭定时器的方法
return () => clearInterval(timer);
}// 测试
const cancel = mySetTimeout(() => {
console.log(1);
}, 1000);
// 一秒后打印 1
如果一个构造函数,bind了一个对象,用这个构造函数创建出的实例会继承这个对象的属性吗?为什么?
不会继承,因为根据 this 绑定四大规则,new 绑定的优先级高于 bind 显示绑定,通过 new 进行构造函数调用时,会创建一个新对象,这个新对象会代替 bind 的对象绑定,作为此函数的 this,并且在此函数没有返回对象的情况下,返回这个新建的对象
说一下vue3.0你了解多少?
组件之间的传值有几种方式
1、父传子
2、子传父
3、eventbus
4、ref/$refs
5、$parent/$children
6、$attrs/$listeners
7、依赖注入(provide/inject)
懒加载的实现原理
图片的加载是由
src
引起的,当对src
赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5 的data-xxx
属性来储存图片的路径,在需要加载图片的时候,将data-xxx
中图片的路径赋值给src
,这样就实现了图片的按需加载,即懒加载。注意:
data-xxx
中的xxx
可以自定义,这里我们使用data-src
来定义。懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
使用原生JavaScript实现懒加载:
知识点:
(1)
window.innerHeight
是浏览器可视区的高度(2)
document.body.scrollTop || document.documentElement.scrollTop
是浏览器滚动的过的距离(3)
imgs.offsetTop
是元素顶部距离文档顶部的高度(包括滚动条的距离)(4)图片加载条件:
img.offsetTop < window.innerHeight + document.body.scrollTop;
图示: 代码实现:
文章图片
文章图片
文章图片
文章图片
文章图片
文章图片
CSS中可继承与不可继承属性有哪些
一、无继承性的属性
- display:规定元素应该生成的框的类型
- 文本属性:
- vertical-align:垂直文本对齐
- text-decoration:规定添加到文本的装饰
- text-shadow:文本阴影效果
- white-space:空白符的处理
- unicode-bidi:设置文本的方向
- 盒子模型的属性:width、height、margin、border、padding
- 背景属性:background、background-color、background-image、background-repeat、background-position、background-attachment
- 定位属性:float、clear、position、top、right、bottom、left、min-width、min-height、max-width、max-height、overflow、clip、z-index
- 生成内容属性:content、counter-reset、counter-increment
- 轮廓样式属性:outline-style、outline-width、outline-color、outline
- 页面样式属性:size、page-break-before、page-break-after
- 声音样式属性:pause-before、pause-after、pause、cue-before、cue-after、cue、play-during
- 字体系列属性
- font-family:字体系列
- font-weight:字体的粗细
- font-size:字体的大小
- font-style:字体的风格
- 文本系列属性
- text-indent:文本缩进
- text-align:文本水平对齐
- line-height:行高
- word-spacing:单词之间的间距
- letter-spacing:中文或者字母之间的间距
- text-transform:控制文本大小写(就是uppercase、lowercase、capitalize这三个)
- color:文本颜色
- 元素可见性
- visibility:控制元素显示隐藏
- 列表布局属性
- list-style:列表风格,包括list-style-type、list-style-image等
- 光标属性
- cursor:光标显示为何种形态
推荐阅读
- 滴滴前端二面面试题
- 阿里前端一面面试题(附答案)
- 滴滴前端一面必会面试题
- 高级前端二面高频面试题合集
- 社招前端二面常见面试题
- 腾讯前端面试题
- 京东前端二面高频面试题
- 字节前端面试题
- 字节前端必会面试题