2022.1.18
1.用es5的方式实现promise
resolvePromise(newPromise, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (newPromise === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (x instanceof MyPromise) {
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
x.then((y) => {
this.resolvePromise(newPromise, y, resolve, reject);
}, reject);
} else if (typeof x === 'object' || this.isFunction(x)) {
// 如果 x 为对象或者函数
if (x === null) {
// null也会被判断为对象
return resolve(x);
}
let then = null;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (this.isFunction(then)) {
let called = false;
// 将 x 作为函数的作用域 this 调用
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
(y) => {
// 需要有一个变量called来保证只调用一次.
if (called) return;
called = true;
this.resolvePromise(newPromise, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 e:
if (called) return;
// 否则以 e 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
2022.1.17
1.观察者和订阅-发布的区别,各自用在哪里
| 发布订阅模式 | 观察者模式 |
|---|---|
| 把事情都放在一个盒子里,等发布的时候你把盒子里的事拿出来,发布和订阅没有关系就叫发布订阅;他们都可以叫做发布订阅模式 | vue的响应式用的是观察者模式,因为内部每个属性都会记录它所有的观察者,当属性变化了会通知所有的观察者去更新,观察者模式的发布订阅是有关系的;观察者模式内部有个收集的关系,被观察者要收集观察者 |
| 有个事件中心,不耦合,发布订阅可以指定执行 | 被触发回所有watcher都执行 |
| 大多数时候是异步的(使用消息队列) | 同步的,比如当事件触发 |
| 例子:vue的生命周期,消息队列 | 例子:vue的响应式 |
2.## 对象数组如何去重
可以通过for循环以及reduce方法;通过循环使用hashmap进行去重
var arr = []
var data = [
{id:1,time:'1'},
{id:2,time:'2'},
{id:2,time:'3'},
]
for(let val of data){
arr.push(val.id)
}
var newArr = [];
var newArr2 = [];
for(var i =0;i<arr.length-1;i++){
if(newArr.indexOf(arr[i]) == -1){
newArr.push(arr[i]);
newArr2.push(data[i]);
}
}
data= newArr2;
3.## 怎样选择合适的缓存策略
缓存策略主要还是强缓存和协商缓存的相关概念,两者区别就是在于协商缓存会像服务器发送一次请求,强缓存不向服务器请求数据。通常先走强缓存判断,如果没有命中强缓存会去判断是否满足协商缓存,若都不满足则重新请求数据;
如果是不怎么替换的lib文件 使用强缓存;js png css使用协商缓存
通过更改js的hash值来更新缓存,文件名字不同
还有一种 小于4kb的图片可以使用base64放到内存中
2022.1.13
1.Vue 框架怎么实现对象和数组的监听?
vue 2.0版本
vue框架通过Object.defineProperty实现对对象的监听,通过重写数组的七个方法
pop,unshift,shift,push,sort,reverse,splice
来实现对数组的监听;同时都会用到递归来遍历
2.Vue 中的 key 有什么作用?
给元素打上唯一标识,主要用于diff算法
3.vue组件中 data 为什么是一个函数?
为了组件中的数据不相互影响;data 必须声明为返回一个初始数据对象的函数,
因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,
则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,
我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。
2022.1.12
1. Map和Set区别 常见用法
| Map | Set |
|---|---|
| 对象,键可以是任何数据类型 | 类似数组,Set里面的元素自动去重,不具有顺序 |
| 一般用Map来存储经常变动的数据 | Set常见于去重 |
| 常见用法:set;get;delete;size;has;clear | 常见用法add;delete;size;has;clear |
| 1.在内存固定时, map可比object 节约50%;2.添加,删除, 大量查找,速度优于object | 去重很方便,记得用...转成数组 |
| 包括普通map ,weakmap() |
Map的用法
const map = new Map();
map.set(1,'one')
map.set(2,'two')
console.log('set',map)
console.log('size',map.size)
console.log('get',map.get(2)) //只能输入键名获取对应的键值
console.log('has',map.has(2)) //true
console.log('delete',map.delete(1)) //返回true 删除某个键值对
map.clear() //删除所有的键值对
console.log('clear',map.size) //此处就为0
如何遍历Map呢
for (let key of map) { //遍历键值对
console.log('遍历键值对',key)
}
for (let [key,val] of map) { //遍历键值对
console.log('遍历键值对',key + '=' + val)
}
for (let key of map.keys()) { //遍历键名
console.log('遍历键名',key)
}
for (let val of map.values()) { //遍历键值
console.log('遍历键值',val)
}
for (let vals of map.entries()) { //遍历键值对
console.log('entries',vals)
}
map.forEach(function(key,value,map){ //map的forEach方法有三个参数:key,value和map本身
console.log(key + " = " + value);
console.log('map',map)
})
Set的用法
基本用法
let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add("some text"); // Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2}); // Set(5) {1, 5, "some text", {…}, {…}}
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
类型转换
// Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 Set 转 Array
var myArray = [...mySet]; String
// String 转 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String
去重的作用
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
weakmap
1. 只接受对象作为键名( null 除外) ,不接受其他类型的值作为键名。
2. 它的存在解决 map 无引用自动垃圾回收这一情况;弱引用,而且 WeakMap 的键名所指向的对象,不计入垃圾回收机制。在用delete方法删除后,key会被垃圾回收。
3.正因为key是弱引用,weakmap的key不能枚举。
2. TS中type和interface的区别
| type(类型别名) | interface(接口) |
|---|---|
| 都支持描述一个对象或者函数 | 都支持描述一个对象或者函数 |
| 不能使用extends,要进行扩展的话需要使用交叉类型& 的形式 | 可以使用extends直接进行扩展 |
| 可以使用自动推断 | 不可使用自动推断 |
| 描述类型 | 描述数据结构 |
| 不能 | **能够声明合并 |
| 不可继承 | 可以继承 |
| type 语句中可以使用 typeof 获取实例的类型进行赋值:type T = typeof 变量 | 不可以 |
| 可以声明基本类型别名,联合类型,元组等类型 | 只能声明对象的形状,不能重命名原始的类型(string、number等) |
// 当type需要继承interface的时候可以利用合并的方式实现:
interface Name {
name: string;
}
type User = Name & {
age: number;
}
3. CDN如何实现加速
CDN全名是内容分发网络,当用户发送请求到达服务器时,服务器会根据用户的区域信息,
为用户分配最近的CDN服务器,而CDN就近的网络节点,不仅能提高用户的访问速度,
也能减少服务器的带宽消耗,降低负载。
在用户和服务器间加入中间层CDN,利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。 CDN关键技术
- 缓存算法决定命中率、源服务器压力、POP节点存储能力
- 分发能力取决于IDC能力和IDC策略性分布
- 负载均衡(智能调度)决定最佳路由、响应时间、可用性、服务质量
- 基于DNS的负载均衡以CNAME实现[to cluster],智取最优节点服务
- 缓存点有客户端浏览器缓存、本地DNS服务器缓存
- 缓存内容有DNS地址缓存、客户请求内容缓存、动态内容缓存
- 支持协议如静动态加速(图片加速、https带证书加速)、下载加速、流媒体加速、企业应用加速、手机应用加速
- 当 cdn 缓存服务器中没有符合客户端要求的资源的时候,缓存服务器会请求上一级缓存服务器,以此类推,直到获取到。最后如果还是没有,就会回到我们自己的服务器去获取资源。
- 没有资源,资源过期,访问的资源是不缓存资源等都会导致回源。