網上看到的字節面試題,蚍蜉撼樹寫下答案

前言

今天早上起來打算繼續寫作作字節面試題系列的文章,在get了排版技巧後(緋紅主題真香),以前的文章就變得不忍直視了,怪不得閱讀量不高。css

這個時候確定有小夥伴會嘀咕:不會覺得你排版好看閱讀量就高了吧?並且你這排版也很差看。哈哈,慢慢來嘛,目前Yiming仍是個小白,只要心態好,閱讀低不了!html

每篇的前言(廢話)部分就到這裏,把當下做爲新的起點,沖沖衝!前端

猛戳這裏查看原文webpack

1px的問題能夠如何去解決【儘量地多說】

出現1px的緣由是設計圖上的1px指的是設備像素,而不是CSS像素。DPR這個視網膜屏幕的概念最早是由蘋果公司提出,計算公式:DPR = CSS像素 / 設備像素。程序員

以IPhone 6爲例,DPR = 750 / 375 = 2,在DPR爲2的屏幕下,1px的物理像素會以2px渲染出來,這裏給幾個思路:web

  • 咱們能夠用0.5px的CSS像素;
  • 修改viewport
  • 僞類+scale,先給僞類設200%的寬度,而後再transform:scaleY(0.5)

最有效的是,無論設計師怎麼催咱們,就是不改!哈哈,開個玩笑,這個問題以前瞭解的比較少,若是Yiming在工做中碰到了這種狀況,Yiming會和設計師多溝通下,若是溝通無果,那就只能改了,哭唧唧~面試

(設計師:看到沒?只要逼着他改,他就會和Yiming同樣改的,因此逼就完事了!)算法

Less和CSS的區別,Less的函數有了解過麼

less是css預處理器,可讓咱們寫出易於維護的css代碼,不過Yiming在工做中只用它來申明過全局變量,這裏就丟個官網的連接吧:http://lesscss.cn/functionsjson

在瀏覽器輸入一個URL的總體過程是怎麼樣的

這個問題通常都會問,由於每個步均可以進行延伸,也不知道是哪一個老哥想出來的鬼才面試題,下面是個人理解:canvas

  1. 當咱們在瀏覽器地址欄按下鍵盤的時候,瀏覽器就會啓動一個算法去書籤欄和歷史記錄中按照咱們輸入的字母進行篩選、展現一個咱們可能會訪問的URL

  2. 當咱們選定了URL按下回車時,瀏覽器就會開始構建請求行,而後檢測這個域名是否合法,若是合法就將此任務給網絡請求線程

  3. 構建好請求行後就會去檢測強緩存是否有效(這個步驟不會發送網絡請求),若是無效,就會開始調用DNS協議進行域名解析,若是以前訪問過這個URL,那麼瀏覽器會把DNS解析後的IP地址保存下來,下次訪問就直接命中(大概能夠節約50~200ms),若是沒有就須要去網絡運營商或者DNS服務器上尋找

  4. 拿到DNS解析的IP地址後,就會構建HTTP請求,開始TCP三次握手創建穩定連接:客戶端向服務器發送一個SYN(同步序列編碼),服務端收到後返回一個新的SYN + ACK(在第一個SYN上作計算後生成的回覆消息),客戶端收到後回覆一個ACK,三次握手創建完畢。爲何是三次?兩次太少,四次太多

  5. 創建好三次握手後,TCP協議爲了傳輸方便,會將HTTP報文切割並編碼成一個個數據包,隨後轉交給網絡層

  6. 網絡層拿到這些數據包後,經過IP地址,配合ARP協議反查出MAC地址,開始傳輸數據 服務器收到這些數據後,將在TCP傳輸層協議中被分割的報文還原成完整的,這個時候通常會校驗是否有權限、是否設置了緩存以及是否過時等。若是設置了協商緩存,那麼會返回304狀態碼通知瀏覽器使用協商緩存(這裏能夠把協商緩存的字段也說下),不然開始響應。響應完畢後,服務器會判斷Connection字段是否爲keep-alive(在HTTP 1.1中是默認值),不是則斷開

  7. 接下來就是瀏覽器開始解析請求到的文件,首先調用GUI線程並行解析HTML和CSS文件,對HTML文件使用標記化和建樹算法,根據文件中設置的<!DOCTYPE>標準來生成DOM樹,對CSS文件進行格式化和標準化生成CSSOM樹,最後合併成合成樹。注意HTML和CSS文件解析是互不影響的,可是會影響最後的合成樹生成的速度,因此CSS文件中不要放@import,它老是在CSS文件解析完畢後再去加載對應的資源

  8. 另外GUI線程和JS線程是互斥的,當解析到HTML文件中的script標籤時,就會掛起GUI線程,從而阻塞渲染,因此script標籤中不要寫async,它老是異步加載,而後當即執行,但你能夠寫defer 拿到合成樹後,爲了提升渲染效率,由於複雜的圖層老是會由GUP單獨繪製(GPU加速),不會影響其餘的圖層,因此開始建立圖層樹。普通文檔流能夠算是複雜圖層,除此以外absolute、transform、opacity、canvas等元素都能造成複雜圖層,因此說動畫最好放在absolute等元素上、用transform代替left/top

  9. 瀏覽器將這些圖層的繪製生成一個個繪製指令,而後交給合成池去進行繪製,生成圖塊和位圖,最後顯示出當前的頁面

這個答案還能夠更詳細,兄弟萌,能夠下去本身再補充下哦!

描述一下瀏覽器頁面渲染的過程

能夠看上一題

瀏覽器白屏是什麼致使的

我這裏就從兩個方面來答吧:

  • 網絡階段,好比第一次訪問沒有緩存DNS對應的IP地址,網站設置了301跳轉等等

  • 渲染階段。咱們知道瀏覽器在拿到文件後會將它們解析成對應的DOM和CSSOM,這裏有兩個方面:第一個方面,因爲瀏覽器的GUI渲染線程和JS線程互斥,因此碰到script標籤就會先對JS文件進行解析,從而阻塞渲染,因此要注意書寫的位置;第二個方面,若是CSS文件中有@import,那麼它會在CSS解析完畢後再進行加載,一樣會形成阻塞。

還能夠繼續說下去~

瀏覽器存儲Cookie、localStorage、sessionStorage的區別

Cookie

因爲HTTP是無狀態的應用層協議,致使服務器沒法記住客戶端用戶的操做,而Cookie主要用來記錄用戶的身份信息,它的大小隻有4kb,無論服務端是否須要用到它,它老是被來回的傳遞(但不支持跨域),它和HTTP緩存同樣,也能夠經過設置max-age和expires字段決定過時時間。

在安全上,因爲JS腳本能夠讀取Cookie,因此咱們得經過Set-Cookie中設置httpOnly禁止JS讀取,預防XSS攻擊。除此以外,不該該用Cookie傳遞敏感信息。

因此能夠看出Cookie主要是用來維持狀態,而不是作本地存儲的

localStorage

H5中新提出的Web存儲技術,大小是5MB,遠大於Cookie體積。因爲保存在瀏覽器端,因此咱們能夠直接經過API調用:

  • 存:localStorage.setItem("key","value")
  • 取:localStorage.getItem("key")

它的生命週期是永久,除非手動清除。應用場景上,咱們能夠用它來保存圖片這種內容穩定的資源

sessionStorage

和localStorage同樣,不只都是H5提出的Web存儲技術,並且用法和空間大小也極爲類似,最大不一樣的地方有兩點:

  • sessionStorage的生命週期是當前標籤頁關閉
  • 沒法跨標籤頁訪問,也就是Tab

相同點是它們三個都是存在客戶端,且沒法跨域

感興趣能夠看這位大佬:https://juejin.cn/post/6844903812092674061

Cookie如何進行設置的,JS能改變哪些值

要搞清楚這個問題,咱們得先去看看Cookie它保存的有哪些值?

name

這個就是Cookie的name,所以同域名下的Cookie會被name值相同的覆蓋掉

value

由於Cookie是以key-value的形式存儲的,因此這裏的value就是對應的屬性值,且必須通過URL編碼

domain

這個就指的是域名,這裏有一個小知識點,只有域名徹底相同才能夠共用一個Cookie,好比,www.manice.com和play.mdnice.com是沒法共用一個Cookie的,不過能夠經過設置domain爲頂級域名就能夠公用了,具體的你們能夠百度,一搜一大把

HttpOnly

這個想必你們比較的熟悉,預防XSS攻擊的,設置爲true後,JS腳本就沒法讀取到Cookie裏面的值

還有一些諸如path、secure等就不一一贅述了,因此JS腳本能讀到Cookie,那就能夠對其進行更改

描述一下瀏覽器緩存

這個部分有不少內容能夠說:

強緩存

不須要發送HTTP請求,只會構建請求行,根據HTTP協議的不一樣分爲兩種:

HTTP 1.0中的Expires,過時時間,潛在的問題是服務器時間和客戶端時間不一致

HTTP 1.1中的Cache-Control,能夠設置max-age來設置緩存生效時間,超過期間段就須要從新發起請求,關於Cache-Control還有不少屬性:

  • max-age:資源最大有效時間
  • no-cache:不緩存,但實際上每次在請求靜態資源的時候會向服務端發送一個過時認證請求,須要配合ETag或者last-modified
  • no-store:始終都去服務端請求最新資源,優先級最高
  • private/public:在請求資源的時候,可能會通過一些CND、Nginx中間代理服務器,若是設置了private,在max-age過時的狀況下,即便中間服務器提示可使用本地緩存資源,依然會向原服務器發送請求,而public相反
協商緩存

須要請求頭中添加tag,服務器根據tag來判斷是否使用緩存,因此被稱爲協商緩存。tag分爲兩種Last-Modified和ETag

  • Last-Modified

最後修改時間。在第一次請求完畢後,服務器給瀏覽器返回的響應頭裏會帶有Last-Modified,瀏覽器在下一次請求的時候會攜帶If-Modified-Since,表示服務器資源最後修改時間,最後進行相應的操做。不然返回304,但只能以秒爲單位,因此不夠精準(不在乎這幾秒的差距也OK)

  • ETag

ETag是給當前的文件資源添加惟一的文件標識,只要內容有改動就值就會變。服務器會將其加在響應頭中,瀏覽器會在下次請求的時候將其做爲If-None-Match字段的內容發送給服務器。服務器根據值作不一樣的操做

  • 二者對比:

ETag優先級比Last-Modified高,由於它能夠精確的判斷是否須要更新。雖然性能不如Last-Modified

緩存位置

強緩存和協商緩存的位置按優先級排列分別是:

  • Service Worker

借鑑了Web Worker,讓JS運行在主線程以外,脫離了瀏覽器窗體,因此也沒法訪問DOM,但能夠幫助咱們實現離線緩存、網絡代理等功能

  • Memory Cache

內存緩存。存取最快,但壽命很短

  • Disk Cache

硬盤緩存。存取慢,壽命長,空間也大,若是緩存內容過大,那麼就用這種方法,不然是內存緩存

  • Push Cache

推送緩存。HTTP 2.0的內容,只存儲在session中,當會話結束後就會被釋放,並且在Chrome瀏覽器中只會保存5分鐘

  • Cookie策略機制

它是一個用於服務端和客戶端之間的認證,當服務端返回了這個cookie,那麼每次請求這個域名下資源的時候(即便是二級域名也會帶),都會帶上這個cookie,且若是不設置cookie的過時時間,只要關閉了瀏覽器,cookie就會失效,因此能夠經過設置max-age

另外出於安全考量,咱們須要給cookie設置一個httpOnly,設置secure cookie,只有在https服務下才會在application/cookie中寫入cookie

反作用

有的時候緩存反而礙事,由於瀏覽器會對html文件進行一個自動的緩存,因此咱們最好在進行聯調的時候設置一個:

<meta http-equiv='Cache-Control' content='no-cache' />
複製代碼
總結

首先會經過Cache-Control判斷可以使用強緩存

若是不能夠則使用協商緩存,服務器經過判斷請求頭中的If-Modified-Since和If-None-Match判斷資源是否更新?

  • 更新:返回200以及最新內容

  • 無更新:返回304以及使用緩存中的資源

較爲穩妥的實踐

先說說強緩存和協商緩存的問題點:

  • 強緩存:設置了cache-control字段,那麼若是服務器的資源忽然更新了,用戶看到的內容就不是最新的了,固然你要是能接受那就OK

  • 協商緩存:每次都會去詢問一次服務器資源是否有更新,仍是會形成必定的資源浪費,畢竟咱們是追求極致的程序員

那麼最好的方案是配合Webpack:

  1. HTML文件:使用協商緩存
  2. CSS、JS和圖片:使用強緩存,而且給文件名都附帶上Hash值

contentHash的講究

當css文件hash改變的時候,js文件hash也會隨之改變,因此咱們能夠在webpack打包的時候使用contentHash

你們也能夠自行到掘金查看更爲詳細的解法

HTTP的狀態碼有哪些

這裏講下Yiming比較經常使用的吧

1XX
  • 100:等待後續處理,好比POST請求發送大實體數據時
2XX
  • 200:請求成功處理,且返回了請求的數據
  • 204:請求成功處理,但沒有返回任何實體部分
3XX
  • 301:永久重定向跳轉(重定向可能會下降網頁的打開速度)
  • 302:臨時重定向跳轉(由於是臨時跳轉,因此也不會進行緩存)
  • 304:沒有資源更新,熟悉緩存的小夥伴應該知道這個狀態碼
4XX
  • 401:須要認證,前端鑑權中會用到這個狀態碼
  • 403:對當前資源沒有訪問權限
  • 404:沒有請求的資源
5XX
  • 502:服務器正常,但發生未知錯誤。當用戶帳號或密碼填錯時,會出現這個狀態碼
  • 503:服務器處於停機維護中,也就是沒有開啓

更多狀態碼可看:

  • https://juejin.cn/post/6844903519447678990

HTTP的請求頭包含什麼

哈~又是一個很長的答案,這裏講下Yiming經常使用的吧:

  • Connection:表示是否須要長鏈接。在HTTP/1.1中默認爲keep-alive,能夠設置close字段關閉
  • Cache-Control:表示緩存機制,它有多個字段,如no-cache、no-store等等
  • Cookie:用來作狀態存儲,解決HTTP協議中沒法保存用戶狀態的弊端,無論請求中是否須要,都會將保存在當前域下的全部cookie傳遞給服務器
  • 還有協商緩存相關的,If-None-Match、If-Match、If-Modified-Since、If-Unmodified-Since
  • Referer:請求來源,能夠用來預防CSRF攻擊
  • Upgrade:指定某種協議,好比指定使用Websocket協議通訊

更多:https://segmentfault.com/a/1190000006689767

解決跨域的方法有哪幾種

也是一個有不少答案,我在工做中只用到過CORS和Nginx反向代理,這裏就不贅述了,掘金一搜一大把~不嫌棄的話也能夠看看我這篇:

  • https://juejin.cn/post/6844904148022870023

描述一下JSONP的原理

由於script中的src屬性不受同源策略影響,因此咱們能夠先在全局定義一個回調函數,而後在Ajax請求時,將函數名做爲參數傳遞,當服務器返回數據到客戶端時就會以前咱們以前定義好的回調函數,這裏給一下代碼:

// 接收三個參數,要發起請求的URL、請求的參數、回調函數
function jsonp({ url, params, cb }) {  // 這裏是拼接參數的方法  let createUrl = () => {  // 申明一個字符串  let dataStr = ''  // for...in循環遍歷參數  for (let k in params) {  // 進行拼接  dataStr += `${k}=${params[k]}&`  }  // 最後將回調函數也加上去  dataStr += `callback=${cb}`  // 返回最終的結果  return `${url}?${dataStr}`  }  // 返回一個Promise對象  return new Promise((resolve, reject) => {  // 在頁面上建立script標籤  let script = document.createElement('script')  // 將script標籤中的src屬性設置爲上面函數返回的參數  script.src = createUrl()  // 將script標籤插入到body中  document.body.appendChild(script)  // 添加回調  window[cb] = data => {  // 成功的回調,會將咱們要請求的參數做爲參數傳入  resolve(data)  // 執行完畢後移除script標籤  document.body.removeChild(script)  }  }) } 複製代碼

描述一下CORS的過程

CORS這個是後端進行處理的,但前端也得懂點。CORS翻譯過來就是Cross-Origin-Resource-Shared,即跨域資源共享,它分爲簡單請求和複雜請求,複雜請求又會多發一次預檢請求,不過預檢請求也不必定就是安全的,依然要注意CSRF攻擊

服務端設置了Access-Control-Allow-Origin,也就是資源控制容許源(感受翻譯過來怪怪的),就會開啓CORS,每次瀏覽器在發送請求的時候都會帶上Origin字段,它由協議、域名和端口號組成,如:

Origin: https://127.0.0.0:8080
複製代碼

而後讓服務端判斷是否能夠給Origin這個源返回數據。這裏沒有詳細的介紹CORS,篇幅有點長,因此就給你們指一條路:

  • https://juejin.cn/post/6844904094973296654

寫在最後

到這裏就結束了,感謝你們的觀看。雖而後面還有不少的題目沒寫,但考慮到那些題目的含金量比較大,因此想從源碼的角度去進行解答(篇幅天然也不會有這麼長啦~)

若是各位發現答案有誤,懇請留言指出,不能誤導更多的人

本文使用 mdnice 排版

相關文章
相關標籤/搜索