viewer keeper

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容