拼多多前端筆試題(二)
8. 請列舉前端開發過程中,有哪些優化的點需要注意
頁面優化的方法非常多,最好能夠對這些優化方案進行分類,這些方案最好能夠結合實際開發遇到的問題來表述。
優化的方案
一、減少操作量
- 儘量減少 HTTP 請求 1) 合併檔案,比如把多個 CSS 檔案合成一個; 2) CSS Sprites 利用 CSS background 相關元素進行背景圖絕對定位;
- 不要在 HTML 中使用縮放圖片 縮放圖片並沒有減少圖片的容量,只是控制了圖片的大小。
- Image壓縮 使用工具對圖片進行壓縮,保證質量的同時減少了圖片的大小。
- 減少對DOM的操作 減少對DOM的操作,減少頁面的重繪。
二、提前做載入操作
- 對域名進行預解析 例如京東的做法
<link rel="dns-prefetch" href="//misc.360buyimg.com" />
- 預載入元件或延遲載入元件
- 把 CSS 放到內碼表上端 CSS 放到最頂部,瀏覽器能夠有針對性的對 HTML 頁面從頂到下進行解析和渲染。
- 使用 new Image物件,對圖片進行快取
三、提升並行載入
切分元件到多個域 ,提升伺服器的響應能力
四、JavaScript和CSS優化
- 從頁面中剝離 JavaScript 與 CSS 剝離後,能夠有針對性的對其進行單獨的處理策略,比如壓縮或者快取策略。
- 精簡 JavaScript 與 CSS
使用工具壓縮JavaScript和CSS檔案 - 指令碼放到 HTML 內碼表底部
減少對頁面的阻塞。
五、非同步載入
使用Ajax實現非同步載入,例如,滾動頁面載入後面的內容,這種也比較常見。
六、避免重繪和迴流
多次使用節點方法(如:appendChild)繪製頁面,每次都要重新整理頁面一次。效率也就大打折扣了,而使用document_createDocumentFragment()建立一個文件碎片,把所有的新結點附加在其上,然後把文件碎片的內容一次性新增到document中,這也就只需要一次頁面重新整理就可以了。
function parseQueryString(argu){
var str = argu. split('?')[1];
var result = {};
var temp = str.split('&');
for(var i=0; i<temp.length; i++)
{
var temp2 = temp[i].split('=');
result[temp2[0]] = temp2[1];
}
return result;
}
var str = parseQueryString1('http://witmax.cn/index.php?key0=0&key1=1&key2=2');
console.log(str);
10. 請簡述web storage和cookie的區別。
1 、與伺服器互動
Web Storage 中的資料僅在存在本地,不與伺服器發生互動。
Cookie 中的資料會在瀏覽器和伺服器中來回傳遞。
2 、儲存空間
Web Storage 儲存空間更大,可以達到 5M ;Cookie 資料大小不超過 4KB 。
3 、 介面
Web Storage 提供 setItem , getItem , removeItem , clear 等方法
Cookie 需要自己封裝 setCookie , getCookie方法
4 、跨域問題
cookie 需要指定作用域,不可以跨域呼叫,但 Web Storage 可以跨域呼叫
5、 儲存時間
cookie 中的資料在過期時間之前均有效, Web Storage 則不同, sessionStorage 中的 資料在當前瀏覽器視窗關閉後自動刪除, localStorage 持久儲存資料,除非主動刪除資料
注: 但 Cookie 是不可以或缺的: Cookie 的作用是與伺服器進行互動,作為 HTTP 規範的一部分而存在 ,而 Web Storage 僅僅是為了在本地 “ 儲存 ” 更大容量資料而生。
11. 一個頁面從輸入 URL 到頁面載入顯示完成,這個過程中都發生了什麼?
1、輸入地址
當我們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智慧的匹配可能得url了,他會從歷史記錄,書籤等地方,找到已經輸入的字串可能對應的 url,然後給出智慧提示,讓你可以補全url地址。對於google的chrome的瀏覽器,他甚至會直接從快取中把網頁展示出來,就是說,你還沒有按下 enter,頁面就出來了。
2、瀏覽器查詢域名的 IP 地址
1、請求一旦發起,瀏覽器首先要做的事情就是解析這個域名,一般來說,瀏覽器會首先檢視本地硬碟的 hosts 檔案,看看其中有沒有和這個域名對應的規則,如果有的話就直接使用 hosts 檔案裡面的 ip 地址。
2、如果在本地的 hosts 檔案沒有能夠找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地DNS伺服器 。本地DNS伺服器一般都是你的網路接入伺服器商提供,比如中國電信,中國移動。
3、查詢你輸入的網址的DNS請求到達本地DNS伺服器之後,本地DNS伺服器會首先查詢它的快取記錄,如果快取中有此條記錄,就可以直接返回結果,此過程是遞迴的方式進行查詢。如果沒有,本地DNS伺服器還要向DNS根伺服器進行查詢。
4、根DNS伺服器沒有記錄具體的域名和IP地址的對應關係,而是告訴本地DNS伺服器,你可以到域伺服器上去繼續查詢,並給出域伺服器的地址。這種過程是迭代的過程。
5、本地DNS伺服器繼續向域伺服器發出請求,在這個例子中,請求的物件是.com域伺服器。.com域伺服器收到請求之後,也不會直接返回域名和IP地址的對應關係,而是告訴本地DNS伺服器,你的域名的解析伺服器的地址。
6、最後,本地DNS伺服器向域名的解析伺服器發出請求,這時就能收到一個域名和IP地址對應關係,本地DNS伺服器不僅要把IP地址返回給使用者電腦,還要把這個對應關係儲存在快取中,以備下次別的使用者查詢時,可以直接返回結果,加快網路訪問。
3、瀏覽器向 web 伺服器傳送一個 HTTP 請求
拿到域名對應的IP地址之後,瀏覽器會以一個隨機埠(1024<埠<65535)向伺服器的WEB程式(常用的有httpd,nginx等)80埠發起TCP的連線請求。這個連線請求到達伺服器端後(這中間通過各種路由裝置,區域網內除外),進入到網絡卡,然後是進入到核心的TCP/IP協議棧(用於識別該連線請求,解封包,一層一層的剝開),還有可能要經過Netfilter防火牆(屬於核心的模組)的過濾,最終到達WEB程式,最終建立了TCP/IP的連線。
4、伺服器的永久重定向響應
伺服器給瀏覽器響應一個301永久重定向響應,這樣瀏覽器就會訪問http://www.google.com/ 而非http://google.com/。
為什麼伺服器一定要重定向而不是直接傳送使用者想看的網頁內容呢?其中一個原因跟搜尋引擎排名有關。如果一個頁面有兩個地址,就像http://www.yy.com/和http://yy.com/,搜尋引擎會認為它們是兩個網站,結果造成每個搜尋連結都減少從而降低排名。而搜尋引擎知道301永久重定向是什麼意思,這樣就會把訪問帶www的和不帶www的地址歸到同一個網站排名下。還有就是用不同的地址會造成快取友好性變差,當一個頁面有好幾個名字時,它可能會在快取裡出現好幾次。
5、瀏覽器跟蹤重定向地址
現在瀏覽器知道了 “http://www.google.com/“才是要訪問的正確地址,所以它會發送另一個http請求。這裡沒有啥好說的
6、伺服器處理請求
經過前面的重重步驟,我們終於將我們的http請求傳送到了伺服器這裡,其實前面的重定向已經是到達伺服器了,那麼,伺服器是如何處理我們的請求的呢?
後端從在固定的埠接收到TCP報文開始,它會對TCP連線進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTP Request物件,供上層使用。
一些大一點的網站會將你的請求到反向代理伺服器中,因為當網站訪問量非常大,網站越來越慢,一臺伺服器已經不夠用了。於是將同一個應用部署在多臺伺服器上,將大量使用者的請求分配給多臺機器處理。此時,客戶端不是直接通過HTTP協議訪問某網站應用伺服器,而是先請求到Nginx,Nginx再請求應用伺服器,然後將結果返回給客戶端,這裡Nginx的作用是反向代理伺服器。同時也帶來了一個好處,其中一臺伺服器萬一掛了,只要還有其他伺服器正常執行,就不會影響使用者使用。
7、伺服器返回一個 HTTP 響應
經過前面的6個步驟,伺服器收到了我們的請求,也處理我們的請求,到這一步,它會把它的處理結果返回,也就是返回一個HTTP響應。HTTP響應與HTTP請求相似,HTTP響應也由3個部分構成
8、瀏覽器顯示 HTML
WebKit渲染的過程,這個過程包括:
解析html以 構建dom樹 -> 構建render樹 -> 佈局render樹 -> 繪製render樹
9、瀏覽器傳送請求獲取嵌入在 HTML 中的資源(如圖片、音訊、視訊、CSS、JS等等)
其實這個步驟可以並列在步驟8中,在瀏覽器顯示HTML時,它會注意到需要獲取其他地址內容的標籤。這時,瀏覽器會發送一個獲取請求來重新獲得這些檔案。
這些地址都要經歷一個和HTML讀取類似的過程。所以瀏覽器會在DNS中查詢這些域名,傳送請求,重定向等等,不像動態頁面,靜態檔案會允許瀏覽器對其進行快取。有的檔案可能會不需要與伺服器通訊,而從快取中直接讀取,或者可以放到CDN中。
12. 請簡述304快取的原理
參考:http://blog.csdn.net/soonfly/article/details/50953814
如果客戶端傳送的是一個條件驗證(Conditional Validation)請求,則web伺服器可能會返回HTTP/304響應,這就表明了客戶端中所請求資源的快取仍然是有效的,也就是說該資源從上次快取到現在並沒有被修改過.條件請求可以在確保客戶端的資源是最新的同時避免因每次都請求完整資源給伺服器帶來的效能問題.
辨別條件請求
當客戶端快取了目標資源但不確定該快取資源是否是最新版本的時候,就會發送一個條件請求.在Fiddler中,你可以在Headers Inspector查詢相關請求頭,這樣就可以辨別出一個請求是否是條件請求.
在進行條件請求時,客戶端會提供給伺服器一個If-Modified-Since請求頭,其值為伺服器上次返回的Last-Modified響應頭中的日期值,還會提供一個If-None-Match請求頭,值為伺服器上次返回的ETag響應頭的值:
伺服器會讀取到這兩個請求頭中的值,判斷出客戶端快取的資源是否是最新的,如果是的話,伺服器就會返回HTTP/304 Not Modified響應,但沒有響應體.客戶端收到304響應後,就會從快取中讀取對應的資源.
另一種情況是,如果伺服器認為客戶端快取的資源已經過期了,那麼伺服器就會返回HTTP/200 OK響應,響應體就是該資源當前最新的內容.客戶端收到200響應後,就會用新的響應體覆蓋掉舊的快取資源.
只有在客戶端快取了對應資源且該資源的響應頭中包含了Last-Modified或ETag的情況下,才可能傳送條件請求.如果這兩個頭都不存在,則必須無條件(unconditionally)請求該資源,伺服器也就必須返回完整的資源資料.
為什麼要使用條件請求
當用戶訪問一個網頁時,條件請求可以加速網頁的開啟時間(因為可以省去傳輸整個響應體的時間),但仍然會有網路延遲,因為瀏覽器還是得為每個資源生成一條條件請求,並且等到伺服器返回HTTP/304響應,才能讀取快取來顯示網頁.更理想的情況是,伺服器在響應上指定Cache-Control或Expires指令,這樣客戶端就能知道該資源的可用時間為多長,也就能跳過條件請求的步驟,直接使用快取中的資源了.可是,即使伺服器提供了這些資訊,在下列情況下仍然需要使用條件請求:
- 在超過伺服器指定的過期時間之後
- 如果使用者執行了重新整理操作的話
在上節給出的圖片中,請求頭中包含了一個Pragma: no-cache.這是由於使用者使用F5重新整理了網頁.如果使用者按下了CTRL-F5 (有時稱之為“強刷-hard refresh”),你會發現瀏覽器省略了If-Modified-Since和If-None-Match請求頭,也就是無條件的請求頁面中的每個資源.
13. 請實現簡單型別的兩個陣列去重,並把去重後的資料放入一個新的陣列中。
var arr1 =[1, 2, 3, '0','2', '測試','重複',NaN, false];
var arr2 =[3,'1',NaN,'重複', false];
function removeDulMergeArr(arr1,arr2) {
var arr = arr1.concat(arr2);
arr.sort();
console.log(arr);
var temp = [];
while(arr.length>0) {
if(Object.is(arr[0],arr[1])){//ES6中嚴格判斷兩個變數是否相等,比===更嚴格
arr.shift();
}else{
temp.push(arr.shift());
}
}
console.log(temp);
}
removeDulMergeArr(arr1,arr2);
14. 封裝一個函式,作用是判斷一個div在當前螢幕中,可以使用jquery操作符$(提示:一個div在螢幕中可以認為是他的左邊或右邊在螢幕中,以及上邊或下邊在螢幕中)
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#display{
width: 50px;
height: 50px;
position: fixed;
top:10px;
background-color: yellow;
font-size: 12px;
}
body{
height: 17000px;
width: 17000px;
}
</style>
<script>
window.onload = function(event) {
var display = document.getElementById("display");
var ele = document.getElementById("secend");
window.onscroll = function () {
var rect = ele.getBoundingClientRect();
if (rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.bottom >=0 &&
rect.right >=0 &&
rect.left<= (window.innerWidth || document.documentElement.clientWidth)) {
display.innerHTML = "div在可視範圍";
} else {
display.innerHTML = "div不在可視範圍";
}
}
}
</script>
</head>
<body>
<div id="display"></div>
<div id="first" style="height: 700px;width: 700px;background: green"></div>
<div id="secend" style="height: 200px;width: 200px;background: red"></div>
</body>
</html>
15. 請簡述css單位rem,以及rem適合使用的場景。
rem是指相對於HTML根元素的字型大小的單位。
rem適用於響應式佈局,每個元素的寬高、文字大小、行距、補白等一切可以使用長度單位的地方均可使用。
16. 畫出一個內半徑為10px,外邊框白色1px的純紅色圓圈,請寫出css程式碼,className隨意。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.container{
width: 10px;
height: 10px;
border: 1px solid white;
border-radius:50%;//生成圓
background-color: red;
background-clip: padding-box;/*主要考察背景顏色不填充邊框,應該使用的屬性*/
}
</style>
</head>
<body>
<div class="container">
</div>
</body>
</html>
17. 試舉例:3個行內元素與塊級元素
行內元素:a ,label ,input, textarea, select ,img,span,i ,code ,q ,sub, sup
塊級元素:div ul ol li h1~h6 p form table