今天早上起來打算繼續寫作作字節面試題系列的文章,在get了排版技巧後(緋紅主題真香
),以前的文章就變得不忍直視了,怪不得閱讀量不高。css
這個時候確定有小夥伴會嘀咕:不會覺得你排版好看閱讀量就高了吧?並且你這排版也很差看。哈哈,慢慢來嘛,目前Yiming仍是個小白,只要心態好,閱讀低不了!html
每篇的前言(廢話)部分就到這裏,把當下做爲新的起點,沖沖衝!前端
猛戳這裏查看原文webpack
出現1px的緣由是設計圖上的1px指的是設備像素,而不是CSS像素。DPR這個視網膜屏幕的概念最早是由蘋果公司提出,計算公式:DPR = CSS像素 / 設備像素。程序員
以IPhone 6爲例,DPR = 750 / 375 = 2,在DPR爲2的屏幕下,1px的物理像素會以2px渲染出來,這裏給幾個思路:web
最有效的是,無論設計師怎麼催咱們,就是不改!哈哈,開個玩笑,這個問題以前瞭解的比較少,若是Yiming在工做中碰到了這種狀況,Yiming會和設計師多溝通下,若是溝通無果,那就只能改了,哭唧唧~面試
(設計師:看到沒?只要逼着他改,他就會和Yiming同樣改的,因此逼就完事了!)算法
less是css預處理器,可讓咱們寫出易於維護的css代碼,不過Yiming在工做中只用它來申明過全局變量,這裏就丟個官網的連接吧:http://lesscss.cn/functionsjson
這個問題通常都會問,由於每個步均可以進行延伸,也不知道是哪一個老哥想出來的鬼才面試題,下面是個人理解:canvas
當咱們在瀏覽器地址欄按下鍵盤的時候,瀏覽器就會啓動一個算法去書籤欄和歷史記錄中按照咱們輸入的字母進行篩選、展現一個咱們可能會訪問的URL
當咱們選定了URL按下回車時,瀏覽器就會開始構建請求行,而後檢測這個域名是否合法,若是合法就將此任務給網絡請求線程
構建好請求行後就會去檢測強緩存是否有效(這個步驟不會發送網絡請求),若是無效,就會開始調用DNS協議進行域名解析,若是以前訪問過這個URL,那麼瀏覽器會把DNS解析後的IP地址保存下來,下次訪問就直接命中(大概能夠節約50~200ms),若是沒有就須要去網絡運營商或者DNS服務器上尋找
拿到DNS解析的IP地址後,就會構建HTTP請求,開始TCP三次握手創建穩定連接:客戶端向服務器發送一個SYN(同步序列編碼),服務端收到後返回一個新的SYN + ACK(在第一個SYN上作計算後生成的回覆消息),客戶端收到後回覆一個ACK,三次握手創建完畢。爲何是三次?兩次太少,四次太多
創建好三次握手後,TCP協議爲了傳輸方便,會將HTTP報文切割並編碼成一個個數據包,隨後轉交給網絡層
網絡層拿到這些數據包後,經過IP地址,配合ARP協議反查出MAC地址,開始傳輸數據 服務器收到這些數據後,將在TCP傳輸層協議中被分割的報文還原成完整的,這個時候通常會校驗是否有權限、是否設置了緩存以及是否過時等。若是設置了協商緩存,那麼會返回304狀態碼通知瀏覽器使用協商緩存(這裏能夠把協商緩存的字段也說下),不然開始響應。響應完畢後,服務器會判斷Connection字段是否爲keep-alive(在HTTP 1.1中是默認值),不是則斷開
接下來就是瀏覽器開始解析請求到的文件,首先調用GUI線程並行解析HTML和CSS文件,對HTML文件使用標記化和建樹算法,根據文件中設置的<!DOCTYPE>標準來生成DOM樹,對CSS文件進行格式化和標準化生成CSSOM樹,最後合併成合成樹。注意HTML和CSS文件解析是互不影響的,可是會影響最後的合成樹生成的速度,因此CSS文件中不要放@import,它老是在CSS文件解析完畢後再去加載對應的資源
另外GUI線程和JS線程是互斥的,當解析到HTML文件中的script標籤時,就會掛起GUI線程,從而阻塞渲染,因此script標籤中不要寫async,它老是異步加載,而後當即執行,但你能夠寫defer 拿到合成樹後,爲了提升渲染效率,由於複雜的圖層老是會由GUP單獨繪製(GPU加速),不會影響其餘的圖層,因此開始建立圖層樹。普通文檔流能夠算是複雜圖層,除此以外absolute、transform、opacity、canvas等元素都能造成複雜圖層,因此說動畫最好放在absolute等元素上、用transform代替left/top
瀏覽器將這些圖層的繪製生成一個個繪製指令,而後交給合成池去進行繪製,生成圖塊和位圖,最後顯示出當前的頁面
這個答案還能夠更詳細,兄弟萌,能夠下去本身再補充下哦!
能夠看上一題
我這裏就從兩個方面來答吧:
網絡階段,好比第一次訪問沒有緩存DNS對應的IP地址,網站設置了301跳轉等等
渲染階段。咱們知道瀏覽器在拿到文件後會將它們解析成對應的DOM和CSSOM,這裏有兩個方面:第一個方面,因爲瀏覽器的GUI渲染線程和JS線程互斥,因此碰到script標籤就會先對JS文件進行解析,從而阻塞渲染,因此要注意書寫的位置;第二個方面,若是CSS文件中有@import,那麼它會在CSS解析完畢後再進行加載,一樣會形成阻塞。
還能夠繼續說下去~
因爲HTTP是無狀態的應用層協議,致使服務器沒法記住客戶端用戶的操做,而Cookie主要用來記錄用戶的身份信息,它的大小隻有4kb,無論服務端是否須要用到它,它老是被來回的傳遞(但不支持跨域),它和HTTP緩存同樣,也能夠經過設置max-age和expires字段決定過時時間。
在安全上,因爲JS腳本能夠讀取Cookie,因此咱們得經過Set-Cookie中設置httpOnly禁止JS讀取,預防XSS攻擊。除此以外,不該該用Cookie傳遞敏感信息。
因此能夠看出Cookie主要是用來維持狀態,而不是作本地存儲的
H5中新提出的Web存儲技術,大小是5MB,遠大於Cookie體積。因爲保存在瀏覽器端,因此咱們能夠直接經過API調用:
它的生命週期是永久,除非手動清除。應用場景上,咱們能夠用它來保存圖片這種內容穩定的資源
和localStorage同樣,不只都是H5提出的Web存儲技術,並且用法和空間大小也極爲類似,最大不一樣的地方有兩點:
相同點是它們三個都是存在客戶端,且沒法跨域
感興趣能夠看這位大佬:https://juejin.cn/post/6844903812092674061
要搞清楚這個問題,咱們得先去看看Cookie它保存的有哪些值?
這個就是Cookie的name,所以同域名下的Cookie會被name值相同的覆蓋掉
由於Cookie是以key-value的形式存儲的,因此這裏的value就是對應的屬性值,且必須通過URL編碼
這個就指的是域名,這裏有一個小知識點,只有域名徹底相同才能夠共用一個Cookie,好比,www.manice.com和play.mdnice.com是沒法共用一個Cookie的,不過能夠經過設置domain爲頂級域名就能夠公用了,具體的你們能夠百度,一搜一大把
這個想必你們比較的熟悉,預防XSS攻擊的,設置爲true後,JS腳本就沒法讀取到Cookie裏面的值
還有一些諸如path、secure等就不一一贅述了,因此JS腳本能讀到Cookie,那就能夠對其進行更改
這個部分有不少內容能夠說:
不須要發送HTTP請求,只會構建請求行,根據HTTP協議的不一樣分爲兩種:
HTTP 1.0中的Expires,過時時間,潛在的問題是服務器時間和客戶端時間不一致
HTTP 1.1中的Cache-Control,能夠設置max-age來設置緩存生效時間,超過期間段就須要從新發起請求,關於Cache-Control還有不少屬性:
須要請求頭中添加tag,服務器根據tag來判斷是否使用緩存,因此被稱爲協商緩存。tag分爲兩種Last-Modified和ETag
最後修改時間。在第一次請求完畢後,服務器給瀏覽器返回的響應頭裏會帶有Last-Modified,瀏覽器在下一次請求的時候會攜帶If-Modified-Since,表示服務器資源最後修改時間,最後進行相應的操做。不然返回304,但只能以秒爲單位,因此不夠精準(不在乎這幾秒的差距也OK)
ETag是給當前的文件資源添加惟一的文件標識,只要內容有改動就值就會變。服務器會將其加在響應頭中,瀏覽器會在下次請求的時候將其做爲If-None-Match字段的內容發送給服務器。服務器根據值作不一樣的操做
ETag優先級比Last-Modified高,由於它能夠精確的判斷是否須要更新。雖然性能不如Last-Modified
強緩存和協商緩存的位置按優先級排列分別是:
借鑑了Web Worker,讓JS運行在主線程以外,脫離了瀏覽器窗體,因此也沒法訪問DOM,但能夠幫助咱們實現離線緩存、網絡代理等功能
內存緩存。存取最快,但壽命很短
硬盤緩存。存取慢,壽命長,空間也大,若是緩存內容過大,那麼就用這種方法,不然是內存緩存
推送緩存。HTTP 2.0的內容,只存儲在session中,當會話結束後就會被釋放,並且在Chrome瀏覽器中只會保存5分鐘
它是一個用於服務端和客戶端之間的認證,當服務端返回了這個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:
當css文件hash改變的時候,js文件hash也會隨之改變,因此咱們能夠在webpack打包的時候使用contentHash
你們也能夠自行到掘金查看更爲詳細的解法
這裏講下Yiming比較經常使用的吧
更多狀態碼可看:
哈~又是一個很長的答案,這裏講下Yiming經常使用的吧:
更多:https://segmentfault.com/a/1190000006689767
也是一個有不少答案,我在工做中只用到過CORS和Nginx反向代理,這裏就不贅述了,掘金一搜一大把~不嫌棄的話也能夠看看我這篇:
由於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翻譯過來就是Cross-Origin-Resource-Shared
,即跨域資源共享,它分爲簡單請求和複雜請求,複雜請求又會多發一次預檢請求,不過預檢請求也不必定就是安全的,依然要注意CSRF攻擊
服務端設置了Access-Control-Allow-Origin
,也就是資源控制容許源
(感受翻譯過來怪怪的),就會開啓CORS,每次瀏覽器在發送請求的時候都會帶上Origin字段
,它由協議、域名和端口號
組成,如:
Origin: https://127.0.0.0:8080 複製代碼
而後讓服務端判斷是否能夠給Origin這個源返回數據。這裏沒有詳細的介紹CORS,篇幅有點長,因此就給你們指一條路:
到這裏就結束了,感謝你們的觀看。雖而後面還有不少的題目沒寫,但考慮到那些題目的含金量比較大,因此想從源碼的角度
去進行解答(篇幅天然也不會有這麼長啦~)
若是各位發現答案有誤,懇請留言指出,不能誤導更多的人
本文使用 mdnice 排版