美文网首页
viewer keeper

viewer keeper

作者: allen_tian | 来源:发表于2020-11-04 01:29 被阅读0次

    1、浏览器输入url到页面展现经历了哪些过程?

    大致流程

    1、URL 解析
    2、DNS 查询
    3、TCP 连接
    4、处理请求
    5、接受响应
    6、渲染页面

    https://www.cnblogs.com/xianyulaodi/p/6547807.html
    https://juejin.im/post/6844904114506170381
    http://www.dailichun.com/2018/03/12/whenyouenteraurl.html
    https://zhuanlan.zhihu.com/p/80551769

    2、手写节流、防抖函数(搞清节流和防抖的定义先)

    节流:在一定时间段内只执行一次,稀释执行频率

    // 节流
    function throttle2 (fn, time) {
      let timer
      let startTime = +new Date()
      return function () {
        if (timer) clearTimeout(timer)
        let currentTime = +new Date()
        if (currentTime - startTime >= time) {
          fn.apply(this, arguments)
          startTime = currentTime
        } else {
          timer = setTimeout(fn, time)
        }
      }
    }
    
    function throttle (fn, time) {
      let waiting = false
      return function () {
        if (waiting) return
        waiting = true
        setTimeout(function(){
          fn()
          waiting = false
        }, time)
      }
    }
    

    防抖:在一定时间段内没有再次触发事件的情况下执行一次

    document.addEventListener('mousemove', debounce(doMove, 1000))
    
    function doMove () {
      console.log('move')
    }
    // 防抖
    function debounce(fn, time) {
      let timer
      return function () {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          fn.apply(this, arguments)
        }, time)
      }
    }
    

    https://juejin.im/post/6875152247714480136#heading-26
    https://segmentfault.com/a/1190000007676390

    3、promise原理? 手写promise

    Promise 是异步编程的一种解决方案,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,可以避免出现异步操作层层嵌套的回调函数。

    Promise对象有以下两个特点:

    1、对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。

    Promise也有一些缺点。

    首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
    其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
    第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    function Promise (executor) {
      this.status = 'pending '
      this.value = undefined
      this.reason = undefined
      
      resolve: (value) => {
        if (this.status === 'pending') {
          this.status = 'fulfilled'
          this.value = value
        }
      }
      
      reject: (reason) => {
        if (this.status === 'pending') {
          this.status = 'rejected'
          this.reason = reason
        }
      }
      
      executor(resolve, reject)
    }
    
    Promise.prototype.then = (onFulFilled, onRejected) => {
      if (this.status === 'fulfilled') {
        return new Promise((resolve, reject) => {
          let p = onFulFilled(this.value)
          if (p instanceof Promise) {
            p.then(resolve, reject)
          } else {
            resolve(p)
          }
        })
      }
      if (this.status === 'rejected') {
        return new Promise((resolve, reject) => {
          let p = onRejected(this.reason)
          if (p instanceof Promise) {
            p.then(resolve, reject)
          } else {
            reject(p)
          }
        })
      }
    }
    
    Promise.prototype.catch = (fn) => {
      return this.then(null, fn)
    }
    

    https://juejin.im/post/6844903587852582919
    https://juejin.im/post/6875152247714480136#heading-26

    promise.all 功能:
    接收一个包含多个promise的数组作为参数,当全部promise都resolve的时候,按顺序返回结果,当有一个promise状态为reject的话,直接返回这个reject

    // promise.all 实现:
    let promise1 = Promise.resolve(1)
    let promise2 = Promise.reject(2)
    let promise3 = Promise.resolve(3)
    function promiseAll(promises) {
      return new Promise(function(resolve, reject) {
        if (!Array.isArray(promises)) {
          return reject(new TypeError('arguments must be an array'));
        }
        var resolvedCounter = 0;
        var promiseNum = promises.length;
        var resolvedValues = new Array(promiseNum);
        for (var i = 0; i < promiseNum; i++) {
          (function(i) {
            Promise.resolve(promises[i]).then(function(value) {
              resolvedCounter++
              resolvedValues[i] = value
              if (resolvedCounter == promiseNum) {
                return resolve(resolvedValues)
              }
            }, function(reason) {
              return reject(reason)
            })
          })(i)
        }
      })
    }
    promiseAll([promise1, promise2, promise3]).then(res => {
      console.log(res)
    })
    

    https://segmentfault.com/a/1190000010765655

    4、手写深拷贝

    let obj = {
      a: 1,
      b: {
        c: 1
      },
      e: [1,2,3],
      d: function () {console.log(1)}
    }
    obj.obj = obj
    
    function cloneDeep(obj, map = new Map()) {
      let cloneObj = Array.isArray(obj) ? [] : {}
      if (map.get(obj)) {
        return map.get(obj)
      }
      map.set(obj, cloneObj)
      for (let key in obj) {
        if ((typeof obj[key] === 'object') && obj[key] !== null) {
          cloneObj[key] = cloneDeep(obj[key], map)
        } else {
          cloneObj[key] = obj[key]
        }
      }
      return cloneObj
    }
    
    let c = cloneDeep(obj)
    
    c.e[0] = 'fuck'
    c.b.c = 'fuck2'
    console.log(c)
    console.log(obj)
    
    c.d = function () {
      console.log(2)
    }
    c.d()
    obj.d()
    
    new map() 可改为 new WeakMap() 可以提升性能
    
    

    https://juejin.im/post/6844903929705136141
    https://juejin.im/post/6875152247714480136#heading-26
    https://juejin.cn/post/6889327058158092302

    5、vue/react的优缺点?vue和react的区别

    https://juejin.im/post/6844904158093377549

    6、ES6 模块与 CommonJS 模块的差异

    CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
    CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
    CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

    7、MVVM原理

    M(Model)V(View)C(Controller) Model数据模型 view视图 Controller控制器,是视图和数据模型之间的桥梁
    M(Model)V(View)VM(View-Model) 在Model和View之间多了叫做View-Model的一层,将模型与视图做了一层绑定关系,在ViewModel引入之后,视图完全由接口返回数据驱动

    以vue2.0为例:(vue的响应式原理)
    当通过new Vue创建Vue实例的时候会遍历data中的数据,使用Object.defineProperty给对象中的属性添加getter和setter方法进行数据劫持,getter用来依赖收集,setter用来派发更新,同时会创建Dep收集watcher,当模板编译的时候,会生成watcher,使用到data中的数据,会触发数据的getter方法,并通过调用Dep.addSub()方法把watcher收集起来,当数据发生变化的时候,会触发数据的setter方法,同时调用Dep.notify()方法通知所有使用到这个data的watcher调用update()方法进行更新。

    8、call, apply, bind

    // 手写call  例子 https://jsbin.com/nequpirijo/1/edit?js,console
    Function.prototype.myCall = function (context) {
      context = Object(context) || window
      console.log('this', this)
      context.fn = this
      let args = []
      for (let i = 1; i < arguments.length; i++) {
        args.push(`arguments[${i}]`)
      }
      let result = eval('context.fn(' + args + ')')
      delete context.fn
      return result
    }
    
    function bar (name, age) {
      console.log(name)
      console.log(age)
      console.log(this.value)
    }
    let obj = {
      value: '111'
    }
    bar.myCall(obj, 'allen', 18)
    
    // 手写apply  例子 https://jsbin.com/cexucilevu/7/edit?html,js,console
    Function.prototype.myApply = function (context, arr) {
      context = Object(context) || window
      let result
      if (!(arr instanceof Array)) {
        throw '第二个参数必须是数组'
      } else {
        context.fn = this
        let args = []
        for (let i = 0; i < arr.length; i++) {
          args.push('arr[' + i + ']')
        }
        result = eval('context.fn(' + args + ')')
      }
      return result
    }
    
    function bar (name, age) {
      console.log(name)
      console.log(age)
      console.log(this.value)
    }
    
    let obj = {
      value: '111'
    }
    
    // bar.myApply(obj, 11, 22) // error
    bar.myApply(obj, [11, 22])
    

    手写参考
    https://www.cnblogs.com/moqiutao/p/7371988.html
    https://blog.csdn.net/qq_43447509/article/details/115614213

    9、var let const

    https://juejin.im/post/6844903752139276301

    10、http缓存

    http中具有缓存功能的是浏览器缓存,所以http缓存属于客户端缓存,将缓存分为强制缓存和协商缓存。
    1、强制缓存:
    当浏览器缓存中已有所请求的数据时,客户端直接从缓存中获取数据。当浏览器缓存中没有所要请求的数据时,才请求服务端。
    强制缓存机制:服务端响应头中会用Expires和Cache-Control两个字段来表明。
    Expires是服务端返回的缓存过期时间。再次请求的时间小于缓存过期时间,就直接使用缓存数据。
    Cache-Control:

    private: 客户端可以缓存
    public:客户端和代理服务器都可以缓存
    max-age=t: 缓存有效期为t秒
    no-cache: 需要使用协商缓存验证缓存数据
    no-store: 不使用缓存

    2、协商缓存:
    又称对比缓存,客户端会从缓存中获取一个缓存数据的标识,得到标识后请求服务器验证缓存是否失效。
    如果没有失效,服务器返回304,客户端直接从缓存中获取数据;
    如果失效了,服务器返回数据,并更新缓存。
    协商缓存机制:浏览器第一次请求数据时,服务器会将缓存标识与数据一起响应给客户端,客户端将它们备份至缓存中。

    Last-Modified: 服务器在响应请求时,会告诉浏览器资源的最后修改时间。浏览器再次请求服务器的时候请求头会带上if-modified-since字段,值为缓存中的数据最后修改时间,服务端接收到带有if-modified-since的请求,会与被请求资源的最后修改时间作对比,如果文件没有被修改过则返回304,从缓存中获取数据,否则服务端返回更新后的数据。

    last-modified的缺陷在于,资源的修改时间变了,可能资源的实际内容并没有发生改变,为解决这个问题,http1.1推出Etag。

    Etag: 服务器响应请求时,会通过此字段告诉浏览器当前资源在服务端的唯一标识(由服务端生成)。浏览器再次请求此资源的时候请求头会带上if-none-match字段,值为缓存中的资源唯一标识,服务端接收到带有if-none-match的请求,会与被请求资源的唯一标识进行对比。如果相同则标识资源没有修改返回304,从缓存中获取数据,否则服务端返回更新后的数据。

    Etag的缺陷在于,实际应用中由于Etag的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用Etag了。

    tips: 两种缓存机制可以同时存在,强制缓存的优先级高于协商缓存,当强制缓存命中的时候,不再进行协商缓存。

    https://www.zoo.team/article/http-cache
    https://juejin.im/post/6844903517702848526
    https://juejin.im/post/6844903554587574285
    < https://zhuanlan.zhihu.com/p/60950750>全面

    11、跨域

    1、JSONP
    首先是利用script标签的src属性来实现跨域。通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。由于使用script标签的src属性,因此只支持get方法。
    2、cors
    get/post 简单请求设置Access-Control-allow-Origin: *
    delete/put/options 非简单请求,会先发送一个预检请求,告诉服务器,要访问的请求头参数和方式,预检请求响应返回允许访问的地址和方式。

    https://juejin.im/post/6844903936088883207

    12、为什么不要用index做key

    https://juejin.im/post/6844904113587634184

    13、性能优化

    https://www.cnblogs.com/xiaohuochai/p/9178390.html
    https://juejin.im/post/6888848660591968264 讲优化,也讲了由优化引出的部分面试常见问题

    HTTP1.0、HTTP1.1 和 HTTP2.0 的区别

    总结:
    一、http1.0与http1.1区别:
    1、缓存处理:1.0使用expires返回一个绝对过期时间,1.1加入cache-control,last-modefied,etag来做缓存
    2、1.0是短连接的,1.1默认默认开启connection: keep-alive支持长连接,在一个TCP连接上可以传送多个HTTP请求和响应
    3、1.1增加了host字段,可以区分不同虚拟机域名,从而实现了不同的逻辑
    4、1.1新增了部分状态码

    二、http1.1与http2.0区别:
    1、2.0多路复用,同一个TCP连接内可以并行发送请求和接受响应
    2、2.0header压缩
    3、2.0可以设置请求优先级
    4、服务端推送

    https://juejin.im/entry/6844903489596833800
    https://juejin.im/post/6855969722246037518

    http 状态码

    1xx 信息响应
    2xx 成功响应:200 成功
    3xx 重定向:301 永久重定向,302 临时重定向,304 未变化
    4xx 客户端错误:400 语义错误/参数错误,401 没权限,403 拒绝响应,404 not found
    5xx 服务器错误: 500 服务器不知道如何处理,502 bad Gateway 网关报错,504 gateway timeout 网关超时

    nextTick原理(事件循环、宏任务、微任务)

    事件循环 <>
    微任务 宏任务 https://juejin.im/post/6844903814508773383
    nextTick原理 https://juejin.im/post/6844904147804749832

    闭包是什么,闭包的作用

    <>

    原型链

    https://juejin.im/post/6844903475021627400

    面试真题

    git fetch pull 区别

    git fetch 是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。 而 git pull 则是将远程主机的最新内容拉下来后直接合并,即: git pull = git fetch + git merge ,这样可能会产生冲突,需要手动解决。

    promise 实现fetch 的 timeout 功能

    https://www.jianshu.com/p/d66421c826ae

    proxy

    Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
    https://es6.ruanyifeng.com/#docs/proxy

    求嵌套数组的嵌套层数或深度

    题目是2020年3月阿里面试算法题,用递归求解。

    function recursiveMax(input){
        var flag = false;
        var num = [];
        for(var i=0;i<input.length;i++){
            var obj=input[i];
            if(obj instanceof Array){
                flag = true;
                num.push(recursiveMax(obj));   
            }
        }
        if(flag){
           return Math.max.apply(null,num) + 1 ;
        } else {
           return 1
        }
       
    }
    var res = recursiveMax([1,[[2,3,5,[],6,7,8],4,5,6,7],8,9,10]);
    console.log(res) // 4
    

    腾讯一面多叉树

    const tree1: TreeNode = {
          next: {
            a: {
              next: {
                e: {
                  next: {}
                }
              }
            },
            b: {
              next: {}
            }
          }
        };
        const tree2: TreeNode = {
          next: {
            a: {
              next: {
                j: {
                  next: {}
                }
              }
            },
            c: {
              next: {
                f: {
                  next: {}
                }
              }
            }
          }
        };
    
    // 思路:
    // 遍历node1,如果node2中存在相同属性就递归该属性的next
    // 如果node2中不存在相同属性则直接加到node1中
    function mergeTree (node1, node2) {
      if (!Object.keys(node2).length) {
        Object.keys(node1).forEach(item => {
          if (node2.next[item]) {
            mergeTree(node1.next[item], node2.next[item])
          } else {
            node1.next[item] = node2.next[item]
          }
        })
      }
      return node1
    }
    

    面试题目:
    vue路由懒加载
    vue模板为什么只能唯一根节点

    必看

    阿里大佬系列技术文章
    阿里大佬面试题答案1
    阿里大佬面试题答案2
    阿里妹子大佬面试题&其他文章
    模块化AMD/CMD/UMD/CJS/ES6
    模块化另一篇
    https加密原理
    壹题系列
    算法
    一周面试题
    链表

    北邮2年前端文章

    其他

    1、掘金关注者文章过一遍

    https://juejin.im/post/6844904115428917255
    http://47.98.159.95/my_blog/

    非面试相关

    页面顶部进度条: npm NProgress

    相关文章

      网友评论

          本文标题:viewer keeper

          本文链接:https://www.haomeiwen.com/subject/cyswvktx.html