1瓦侮、瀏覽器輸入url到頁面展現(xiàn)經(jīng)歷了哪些過程艰赞?
大致流程
1、URL 解析
2肚吏、DNS 查詢
3方妖、TCP 連接
4、處理請求
5罚攀、接受響應(yīng)
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、手寫節(jié)流斋泄、防抖函數(shù)(搞清節(jié)流和防抖的定義先)
節(jié)流:在一定時間段內(nèi)只執(zhí)行一次杯瞻,稀釋執(zhí)行頻率
// 節(jié)流
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)
}
}
防抖:在一定時間段內(nèi)沒有再次觸發(fā)事件的情況下執(zhí)行一次
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對象募胃,就可以將異步操作以同步操作的流程表達出來抹蚀,可以避免出現(xiàn)異步操作層層嵌套的回調(diào)函數(shù)剿牺。
Promise對象有以下兩個特點:
1、對象的狀態(tài)不受外界影響环壤。Promise對象代表一個異步操作晒来,有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失斨O帧)湃崩。只有異步操作的結(jié)果荧降,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)攒读。
2朵诫、一旦狀態(tài)改變,就不會再變薄扁,任何時候都可以得到這個結(jié)果剪返。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected邓梅。只要這兩種情況發(fā)生脱盲,狀態(tài)就凝固了,不會再變了日缨,會一直保持這個結(jié)果钱反。
Promise也有一些缺點。
首先匣距,無法取消Promise面哥,一旦新建它就會立即執(zhí)行,無法中途取消墨礁。
其次幢竹,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤恩静,不會反應(yīng)到外部焕毫。
第三,當處于pending狀態(tài)時驶乾,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)邑飒。
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的數(shù)組作為參數(shù),當全部promise都resolve的時候级乐,按順序返回結(jié)果疙咸,當有一個promise狀態(tài)為reject的話,直接返回這個reject
// promise.all 實現(xiàn):
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的優(yōu)缺點?vue和react的區(qū)別
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數(shù)據(jù)模型 view視圖 Controller控制器,是視圖和數(shù)據(jù)模型之間的橋梁
M(Model)V(View)VM(View-Model) 在Model和View之間多了叫做View-Model的一層符喝,將模型與視圖做了一層綁定關(guān)系闪彼,在ViewModel引入之后,視圖完全由接口返回數(shù)據(jù)驅(qū)動
以vue2.0為例:(vue的響應(yīng)式原理)
當通過new Vue創(chuàng)建Vue實例的時候會遍歷data中的數(shù)據(jù)协饲,使用Object.defineProperty給對象中的屬性添加getter和setter方法進行數(shù)據(jù)劫持备蚓,getter用來依賴收集,setter用來派發(fā)更新囱稽,同時會創(chuàng)建Dep收集watcher,當模板編譯的時候二跋,會生成watcher战惊,使用到data中的數(shù)據(jù),會觸發(fā)數(shù)據(jù)的getter方法扎即,并通過調(diào)用Dep.addSub()方法把watcher收集起來吞获,當數(shù)據(jù)發(fā)生變化的時候,會觸發(fā)數(shù)據(jù)的setter方法谚鄙,同時調(diào)用Dep.notify()方法通知所有使用到這個data的watcher調(diào)用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 '第二個參數(shù)必須是數(shù)組'
} 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緩存屬于客戶端緩存傻盟,將緩存分為強制緩存和協(xié)商緩存速蕊。
1、強制緩存:
當瀏覽器緩存中已有所請求的數(shù)據(jù)時娘赴,客戶端直接從緩存中獲取數(shù)據(jù)规哲。當瀏覽器緩存中沒有所要請求的數(shù)據(jù)時,才請求服務(wù)端诽表。
強制緩存機制:服務(wù)端響應(yīng)頭中會用Expires和Cache-Control兩個字段來表明唉锌。
Expires是服務(wù)端返回的緩存過期時間。再次請求的時間小于緩存過期時間竿奏,就直接使用緩存數(shù)據(jù)袄简。
Cache-Control:
private: 客戶端可以緩存
public:客戶端和代理服務(wù)器都可以緩存
max-age=t: 緩存有效期為t秒
no-cache: 需要使用協(xié)商緩存驗證緩存數(shù)據(jù)
no-store: 不使用緩存
2、協(xié)商緩存:
又稱對比緩存议双,客戶端會從緩存中獲取一個緩存數(shù)據(jù)的標識痘番,得到標識后請求服務(wù)器驗證緩存是否失效。
如果沒有失效,服務(wù)器返回304汞舱,客戶端直接從緩存中獲取數(shù)據(jù)伍纫;
如果失效了,服務(wù)器返回數(shù)據(jù)昂芜,并更新緩存莹规。
協(xié)商緩存機制:瀏覽器第一次請求數(shù)據(jù)時,服務(wù)器會將緩存標識與數(shù)據(jù)一起響應(yīng)給客戶端泌神,客戶端將它們備份至緩存中良漱。
Last-Modified: 服務(wù)器在響應(yīng)請求時,會告訴瀏覽器資源的最后修改時間欢际。瀏覽器再次請求服務(wù)器的時候請求頭會帶上if-modified-since字段母市,值為緩存中的數(shù)據(jù)最后修改時間,服務(wù)端接收到帶有if-modified-since的請求损趋,會與被請求資源的最后修改時間作對比患久,如果文件沒有被修改過則返回304,從緩存中獲取數(shù)據(jù)浑槽,否則服務(wù)端返回更新后的數(shù)據(jù)蒋失。
last-modified的缺陷在于,資源的修改時間變了桐玻,可能資源的實際內(nèi)容并沒有發(fā)生改變篙挽,為解決這個問題,http1.1推出Etag镊靴。
Etag: 服務(wù)器響應(yīng)請求時铣卡,會通過此字段告訴瀏覽器當前資源在服務(wù)端的唯一標識(由服務(wù)端生成)。瀏覽器再次請求此資源的時候請求頭會帶上if-none-match字段邑闲,值為緩存中的資源唯一標識算行,服務(wù)端接收到帶有if-none-match的請求,會與被請求資源的唯一標識進行對比苫耸。如果相同則標識資源沒有修改返回304州邢,從緩存中獲取數(shù)據(jù),否則服務(wù)端返回更新后的數(shù)據(jù)褪子。
Etag的缺陷在于量淌,實際應(yīng)用中由于Etag的計算是使用算法來得出的,而算法會占用服務(wù)端計算的資源嫌褪,所有服務(wù)端的資源都是寶貴的呀枢,所以就很少使用Etag了。
tips: 兩種緩存機制可以同時存在笼痛,強制緩存的優(yōu)先級高于協(xié)商緩存裙秋,當強制緩存命中的時候琅拌,不再進行協(xié)商緩存。
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屬性來實現(xiàn)跨域。通過將前端方法作為參數(shù)傳遞到服務(wù)器端枷恕,然后由服務(wù)器端注入?yún)?shù)之后再返回党晋,實現(xiàn)服務(wù)器端向客戶端通信。由于使用script標簽的src屬性徐块,因此只支持get方法未玻。
2、cors
get/post 簡單請求設(shè)置Access-Control-allow-Origin: *
delete/put/options 非簡單請求胡控,會先發(fā)送一個預(yù)檢請求扳剿,告訴服務(wù)器,要訪問的請求頭參數(shù)和方式昼激,預(yù)檢請求響應(yīng)返回允許訪問的地址和方式舞终。
https://juejin.im/post/6844903936088883207
12、為什么不要用index做key
https://juejin.im/post/6844904113587634184
13癣猾、性能優(yōu)化
https://www.cnblogs.com/xiaohuochai/p/9178390.html
https://juejin.im/post/6888848660591968264 講優(yōu)化,也講了由優(yōu)化引出的部分面試常見問題
HTTP1.0余爆、HTTP1.1 和 HTTP2.0 的區(qū)別
總結(jié):
一纷宇、http1.0與http1.1區(qū)別:
1、緩存處理:1.0使用expires返回一個絕對過期時間蛾方,1.1加入cache-control,last-modefied,etag來做緩存
2像捶、1.0是短連接的,1.1默認默認開啟connection: keep-alive支持長連接桩砰,在一個TCP連接上可以傳送多個HTTP請求和響應(yīng)
3拓春、1.1增加了host字段,可以區(qū)分不同虛擬機域名亚隅,從而實現(xiàn)了不同的邏輯
4硼莽、1.1新增了部分狀態(tài)碼
二、http1.1與http2.0區(qū)別:
1煮纵、2.0多路復(fù)用懂鸵,同一個TCP連接內(nèi)可以并行發(fā)送請求和接受響應(yīng)
2、2.0header壓縮
3行疏、2.0可以設(shè)置請求優(yōu)先級
4匆光、服務(wù)端推送
https://juejin.im/entry/6844903489596833800
https://juejin.im/post/6855969722246037518
http 狀態(tài)碼
1xx 信息響應(yīng)
2xx 成功響應(yīng):200 成功
3xx 重定向:301 永久重定向,302 臨時重定向酿联,304 未變化
4xx 客戶端錯誤:400 語義錯誤/參數(shù)錯誤终息,401 沒權(quán)限夺巩,403 拒絕響應(yīng),404 not found
5xx 服務(wù)器錯誤: 500 服務(wù)器不知道如何處理周崭,502 bad Gateway 網(wǎng)關(guān)報錯柳譬,504 gateway timeout 網(wǎng)關(guān)超時
nextTick原理(事件循環(huán)、宏任務(wù)休傍、微任務(wù))
事件循環(huán) <>
微任務(wù) 宏任務(wù) https://juejin.im/post/6844903814508773383
nextTick原理 https://juejin.im/post/6844904147804749832
閉包是什么征绎,閉包的作用
<>
原型鏈
https://juejin.im/post/6844903475021627400
面試真題
git fetch pull 區(qū)別
git fetch 是將遠程主機的最新內(nèi)容拉到本地,用戶在檢查了以后決定是否合并到工作本機分支中磨取。 而 git pull 則是將遠程主機的最新內(nèi)容拉下來后直接合并人柿,即: git pull = git fetch + git merge ,這樣可能會產(chǎn)生沖突忙厌,需要手動解決凫岖。
promise 實現(xiàn)fetch 的 timeout 功能
http://www.reibang.com/p/d66421c826ae
proxy
Proxy 對象用于創(chuàng)建一個對象的代理,從而實現(xiàn)基本操作的攔截和自定義(如屬性查找逢净、賦值哥放、枚舉、函數(shù)調(diào)用等)爹土。
https://es6.ruanyifeng.com/#docs/proxy
求嵌套數(shù)組的嵌套層數(shù)或深度
題目是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模板為什么只能唯一根節(jié)點
必看
阿里大佬系列技術(shù)文章
阿里大佬面試題答案1
阿里大佬面試題答案2
阿里妹子大佬面試題&其他文章
模塊化AMD/CMD/UMD/CJS/ES6
模塊化另一篇
https加密原理
壹題系列
算法
一周面試題
鏈表
其他
1社露、掘金關(guān)注者文章過一遍
https://juejin.im/post/6844904115428917255
http://47.98.159.95/my_blog/
非面試相關(guān)
頁面頂部進度條: npm NProgress