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加密原理
壹题系列
算法
一周面试题
链表
其他
1、掘金关注者文章过一遍
https://juejin.im/post/6844904115428917255
http://47.98.159.95/my_blog/
非面试相关
页面顶部进度条: npm NProgress
网友评论