每日一题

144 阅读8分钟

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实现对对象的监听,通过重写数组的七个方法
    popunshiftshiftpushsortreversesplice
    来实现对数组的监听;同时都会用到递归来遍历

2.Vue 中的 key 有什么作用?

    给元素打上唯一标识,主要用于diff算法

3.vue组件中 data 为什么是一个函数?

    为了组件中的数据不相互影响;data 必须声明为返回一个初始数据对象的函数,
    因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,
    则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,
    我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

2022.1.12

1. Map和Set区别 常见用法

MapSet
对象,键可以是任何数据类型类似数组,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 也能存储

类型转换

    // ArraySet 
    var mySet = new Set(["value1", "value2", "value3"]);
    // 用...操作符,将 SetArray 
    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 缓存服务器中没有符合客户端要求的资源的时候,缓存服务器会请求上一级缓存服务器,以此类推,直到获取到。最后如果还是没有,就会回到我们自己的服务器去获取资源。
  • 没有资源,资源过期,访问的资源是不缓存资源等都会导致回源。